diff --git a/Deployment/application.json b/Deployment/application.json index 8741598..703d972 100644 --- a/Deployment/application.json +++ b/Deployment/application.json @@ -1,4 +1,3 @@ { - "flask_secret_key": "secret", "metrics_token": "metrics" } diff --git a/Sources/website/benjaminhamon_developer_website/application.py b/Sources/website/benjaminhamon_developer_website/application.py index 283c0eb..98106dd 100644 --- a/Sources/website/benjaminhamon_developer_website/application.py +++ b/Sources/website/benjaminhamon_developer_website/application.py @@ -29,19 +29,14 @@ def run(self, address: Optional[str] = None, port: Optional[int] = None, debug: self._flask_application.run(host = address, port = port, debug = debug) - def log_request(self) -> None: - request_logger.info("(%s) %s %s", flask.request.environ["REMOTE_ADDR"], flask.request.method, flask.request.base_url) + def check_request(self) -> None: + requested_locale = self._get_requested_locale() + if requested_locale is not None and requested_locale not in self._flask_application.config["LOCALE_SUPPORTED"]: + raise werkzeug.exceptions.NotFound - def refresh_session(self) -> None: - flask.session.permanent = True - - if "locale" in flask.request.args: - flask.session["locale"] = flask.request.args["locale"] - if "locale" not in flask.session: - flask.session["locale"] = "en" - if flask.session["locale"] not in [ "en", "fr" ]: - flask.session["locale"] = "en" + def log_request(self) -> None: + request_logger.info("(%s) %s %s", flask.request.environ["REMOTE_ADDR"], flask.request.method, flask.request.base_url) def handle_error(self, exception: Any) -> flask.typing.ResponseReturnValue: @@ -54,4 +49,14 @@ def handle_error(self, exception: Any) -> flask.typing.ResponseReturnValue: if flask.request.url_rule is not None and flask.request.url_rule.rule == "/metrics": return "", status_code, { "Content-Type": "text/plain" } - return flask.render_template(flask.session["locale"] + "/" + "error.html", message = status_message, status_code = status_code), status_code + requested_locale = self._get_requested_locale() + if requested_locale is None or requested_locale not in self._flask_application.config["LOCALE_SUPPORTED"]: + requested_locale = self._flask_application.config["LOCALE_DEFAULT"] + + return flask.render_template(requested_locale + "/" + "error.html", message = status_message, status_code = status_code), status_code + + + def _get_requested_locale(self) -> Optional[str]: + if flask.request.url_rule is not None and flask.request.view_args is not None: + return flask.request.view_args.get("locale", None) + return flask.request.path.split("/")[1] diff --git a/Sources/website/benjaminhamon_developer_website/application_factory.py b/Sources/website/benjaminhamon_developer_website/application_factory.py index d2e3592..eeb7e45 100644 --- a/Sources/website/benjaminhamon_developer_website/application_factory.py +++ b/Sources/website/benjaminhamon_developer_website/application_factory.py @@ -1,6 +1,5 @@ # cspell:words werkzeug -import datetime import functools import logging from typing import Callable, List @@ -19,19 +18,9 @@ request_logger = logging.getLogger("Request") -def create_application(flask_secret_key: str, metrics_token: str) -> Application: - title = "Benjamin Hamon's developer website" - sources_url = "https://github.com/BenjaminHamon/DeveloperWebsite" - contact_email = "development@benjaminhamon.com" - +def create_application(metrics_token: str) -> Application: flask_application = flask.Flask("benjaminhamon_developer_website") - flask_application.secret_key = flask_secret_key flask_application.config.update( - SECRET_KEY = flask_secret_key, - SESSION_COOKIE_HTTPONLY = True, - SESSION_COOKIE_SAMESITE = "Lax", - SESSION_COOKIE_SECURE = True, - PERMANENT_SESSION_LIFETIME = datetime.timedelta(days = 7), METRICS_TOKEN = metrics_token, ) @@ -39,7 +28,7 @@ def create_application(flask_secret_key: str, metrics_token: str) -> Application application = Application(flask_application) main_controller = MainController() - configure(flask_application, title, sources_url, contact_email) + configure(flask_application) register_handlers(flask_application, application) register_routes(flask_application, main_controller) prometheus_metrics.init_app(flask_application) @@ -47,13 +36,18 @@ def create_application(flask_secret_key: str, metrics_token: str) -> Application return application -def configure(application: flask.Flask, title: str, sources_url: str, contact_email: str) -> None: - application.config["WEBSITE_TITLE"] = title - application.config["WEBSITE_COPYRIGHT"] = benjaminhamon_developer_website.__copyright__ - application.config["WEBSITE_VERSION"] = benjaminhamon_developer_website.__version__ - application.config["WEBSITE_DATE"] = benjaminhamon_developer_website.__date__ - application.config["WEBSITE_SOURCES_URL"] = sources_url - application.config["WEBSITE_CONTACT_EMAIL"] = contact_email +def configure(application: flask.Flask) -> None: + application.config["METADATA"] = { + "product": benjaminhamon_developer_website.__product__, + "copyright": benjaminhamon_developer_website.__copyright__, + "version": benjaminhamon_developer_website.__version__, + "date": benjaminhamon_developer_website.__date__, + "sources_url": "https://github.com/BenjaminHamon/DeveloperWebsite", + "contact_email": "development@benjaminhamon.com", + } + + application.config["LOCALE_DEFAULT"] = "en" + application.config["LOCALE_SUPPORTED"] = [ "en", "fr" ] application.jinja_env.undefined = jinja2.StrictUndefined application.jinja_env.trim_blocks = True @@ -65,18 +59,19 @@ def configure(application: flask.Flask, title: str, sources_url: str, contact_em def register_handlers(flask_application: flask.Flask, application: Application) -> None: flask_application.log_exception = lambda exc_info: None flask_application.before_request(application.log_request) - flask_application.before_request(application.refresh_session) + flask_application.before_request(application.check_request) for exception in werkzeug.exceptions.default_exceptions.values(): flask_application.register_error_handler(exception, application.handle_error) def register_routes(application: flask.Flask, main_controller: MainController) -> None: - add_url_rule(application, "/", [ "GET" ], main_controller.home) - add_url_rule(application, "/contact", [ "GET" ], main_controller.contact) - add_url_rule(application, "/education", [ "GET" ], main_controller.education) - add_url_rule(application, "/projects", [ "GET" ], main_controller.projects) - add_url_rule(application, "/skills", [ "GET" ], main_controller.skills) - add_url_rule(application, "/work_experience", [ "GET" ], main_controller.work_experience) + add_url_rule(application, "/", [ "GET" ], main_controller.home_default) + add_url_rule(application, "/", [ "GET" ], main_controller.home) + add_url_rule(application, "//contact", [ "GET" ], main_controller.contact) + add_url_rule(application, "//education", [ "GET" ], main_controller.education) + add_url_rule(application, "//projects", [ "GET" ], main_controller.projects) + add_url_rule(application, "//skills", [ "GET" ], main_controller.skills) + add_url_rule(application, "//work_experience", [ "GET" ], main_controller.work_experience) def add_url_rule(application: flask.Flask, path: str, methods: List[str], handler: Callable, **kwargs) -> None: @@ -86,7 +81,7 @@ def add_url_rule(application: flask.Flask, path: str, methods: List[str], handle def versioned_url_for(endpoint: str, **values) -> str: if endpoint == "static": - values["version"] = flask.current_app.config["WEBSITE_VERSION"] + values["version"] = flask.current_app.config["METADATA"]["version"] return flask.url_for(endpoint, **values) diff --git a/Sources/website/benjaminhamon_developer_website/main_controller.py b/Sources/website/benjaminhamon_developer_website/main_controller.py index 218e7f1..50b15b0 100644 --- a/Sources/website/benjaminhamon_developer_website/main_controller.py +++ b/Sources/website/benjaminhamon_developer_website/main_controller.py @@ -1,28 +1,33 @@ import flask +import werkzeug class MainController: - def home(self) -> str: - return flask.render_template(flask.session["locale"] + "/" + "home.html") + def home_default(self) -> werkzeug.Response: + return flask.redirect(flask.url_for("main_controller.home", locale = flask.current_app.config["LOCALE_DEFAULT"])) - def education(self) -> str: - return flask.render_template(flask.session["locale"] + "/" + "education.html") + def home(self, locale: str) -> str: + return flask.render_template(locale + "/" + "home.html") - def skills(self) -> str: - return flask.render_template(flask.session["locale"] + "/" + "skills.html") + def education(self, locale: str) -> str: + return flask.render_template(locale + "/" + "education.html") - def projects(self) -> str: - return flask.render_template(flask.session["locale"] + "/" + "projects.html") + def skills(self, locale: str) -> str: + return flask.render_template(locale + "/" + "skills.html") - def work_experience(self) -> str: - return flask.render_template(flask.session["locale"] + "/" + "work_experience.html") + def projects(self, locale: str) -> str: + return flask.render_template(locale + "/" + "projects.html") - def contact(self) -> str: - return flask.render_template(flask.session["locale"] + "/" + "contact.html") + def work_experience(self, locale: str) -> str: + return flask.render_template(locale + "/" + "work_experience.html") + + + def contact(self, locale: str) -> str: + return flask.render_template(locale + "/" + "contact.html") diff --git a/Sources/website/benjaminhamon_developer_website/run.py b/Sources/website/benjaminhamon_developer_website/run.py index e6debe0..f5a8293 100644 --- a/Sources/website/benjaminhamon_developer_website/run.py +++ b/Sources/website/benjaminhamon_developer_website/run.py @@ -20,7 +20,7 @@ def main(): configure_logging(arguments) - application = application_factory.create_application("secret", "metrics") + application = application_factory.create_application("metrics") website_url = "http://%s:%s/" % (arguments.address, arguments.port) os.environ["DEBUG_METRICS"] = "1" # For Prometheus exporter diff --git a/Sources/website/benjaminhamon_developer_website/templates/en/contact.html b/Sources/website/benjaminhamon_developer_website/templates/en/contact.html index f3f05f5..e8aa6b9 100644 --- a/Sources/website/benjaminhamon_developer_website/templates/en/contact.html +++ b/Sources/website/benjaminhamon_developer_website/templates/en/contact.html @@ -15,7 +15,7 @@ work@benjaminhamon.com
-

Please use this address for work-related inquiries. See my status on the Home page.

+

Please use this address for work-related inquiries. See my status on the Home page.

diff --git a/Sources/website/benjaminhamon_developer_website/templates/en/home.html b/Sources/website/benjaminhamon_developer_website/templates/en/home.html index 142d8a6..61d9530 100644 --- a/Sources/website/benjaminhamon_developer_website/templates/en/home.html +++ b/Sources/website/benjaminhamon_developer_website/templates/en/home.html @@ -22,7 +22,7 @@

Hello! I'm Benjamin.

I'm a 33-year-old French guy with a passion for video games and most computer-related things.

I've worked as a software engineer in the video game industry for about a decade. I typically go by DevOps engineer, and I'm proficient in application development, web development, system administration, and infrastructure management. While I'm not your usual game programmer, you might have glimpsed my name in the credits of such games as Humankind and Life Is Strange 2.

-

I work on several open source projects, which you can explore in the Projects page and through GitHub.

+

I work on several open source projects, which you can explore in the Projects page and through GitHub.

As another matter entirely, I recently became a self-published novelist. If that interests you, you can check out my author website and my blog about fiction.

diff --git a/Sources/website/benjaminhamon_developer_website/templates/en/layout.html b/Sources/website/benjaminhamon_developer_website/templates/en/layout.html index 0bce06a..d6ac9ee 100644 --- a/Sources/website/benjaminhamon_developer_website/templates/en/layout.html +++ b/Sources/website/benjaminhamon_developer_website/templates/en/layout.html @@ -1,4 +1,4 @@ -{# cspell:words stylesheet #} +{# cspell:words français hreflang stylesheet #} {% import 'macros.html' as shared_macros -%} @@ -6,27 +6,35 @@ - {{ title }} - {{ config['WEBSITE_TITLE'] }} + + {{ title }} - Benjamin Hamon's developer website + + {% if request.url_rule %} + + + + {% endif %} +
@@ -38,21 +46,21 @@