From 477477edae2851a67086b0447e425de5949b2f7f Mon Sep 17 00:00:00 2001 From: Yax <1949284+kianby@users.noreply.github.com> Date: Fri, 12 Apr 2024 21:25:27 +0200 Subject: [PATCH] Refactor application startup. Use Flask app config and remove package singletons --- src/stacosys/interface/__init__.py | 7 +-- src/stacosys/interface/form.py | 3 +- src/stacosys/interface/web/admin.py | 15 +++-- src/stacosys/run.py | 87 ++++++++++++++++------------- src/stacosys/service/__init__.py | 10 ---- 5 files changed, 58 insertions(+), 64 deletions(-) delete mode 100644 src/stacosys/service/__init__.py diff --git a/src/stacosys/interface/__init__.py b/src/stacosys/interface/__init__.py index d72483d..c6211a4 100644 --- a/src/stacosys/interface/__init__.py +++ b/src/stacosys/interface/__init__.py @@ -7,7 +7,6 @@ import background from flask import Flask from stacosys.db import dao -from stacosys.service import config, mailer from stacosys.service.configuration import ConfigParameter app = Flask(__name__) @@ -20,7 +19,7 @@ logger = logging.getLogger(__name__) @background.task def submit_new_comment(comment): - site_url = config.get(ConfigParameter.SITE_URL) + site_url = app.config['CONFIG'].get(ConfigParameter.SITE_URL) comment_list = ( f"Web admin interface: {site_url}/web/admin", "", @@ -35,9 +34,9 @@ def submit_new_comment(comment): email_body = "\n".join(comment_list) # send email to notify admin - site_name = config.get(ConfigParameter.SITE_NAME) + site_name = app.config['CONFIG'].get(ConfigParameter.SITE_NAME) subject = f"STACOSYS {site_name}" - if mailer.send(subject, email_body): + if app.config['MAILER'].send(subject, email_body): logger.debug("new comment processed") # save notification datetime dao.notify_comment(comment) diff --git a/src/stacosys/interface/form.py b/src/stacosys/interface/form.py index 8513438..72e5e52 100644 --- a/src/stacosys/interface/form.py +++ b/src/stacosys/interface/form.py @@ -6,7 +6,6 @@ from flask import abort, redirect, request from stacosys.db import dao from stacosys.interface import app, submit_new_comment -from stacosys.service import config from stacosys.service.configuration import ConfigParameter logger = logging.getLogger(__name__) @@ -47,7 +46,7 @@ def new_form_comment(): # send notification e-mail asynchronously submit_new_comment(comment) - return redirect(config.get(ConfigParameter.SITE_REDIRECT), code=302) + return redirect(app.config['CONFIG'].get(ConfigParameter.SITE_REDIRECT), code=302) def check_form_data(posted_comment): diff --git a/src/stacosys/interface/web/admin.py b/src/stacosys/interface/web/admin.py index 8d81e3c..4c8b9dd 100644 --- a/src/stacosys/interface/web/admin.py +++ b/src/stacosys/interface/web/admin.py @@ -8,7 +8,6 @@ from flask import flash, redirect, render_template, request, session from stacosys.db import dao from stacosys.interface import app -from stacosys.service import config, rss from stacosys.service.configuration import ConfigParameter logger = logging.getLogger(__name__) @@ -25,8 +24,8 @@ def index(): def is_login_ok(username, password): hashed = hashlib.sha256(password.encode()).hexdigest().upper() return ( - config.get(ConfigParameter.WEB_USERNAME) == username - and config.get(ConfigParameter.WEB_PASSWORD) == hashed + app.config['CONFIG'].get(ConfigParameter.WEB_USERNAME) == username + and app.config['CONFIG'].get(ConfigParameter.WEB_PASSWORD) == hashed ) @@ -42,7 +41,7 @@ def login(): flash("Identifiant ou mot de passe incorrect") return redirect("/web/login") # GET - return render_template("login_" + config.get(ConfigParameter.LANG) + ".html") + return render_template("login_" + app.config['CONFIG'].get(ConfigParameter.LANG) + ".html") @app.route("/web/logout", methods=["GET"]) @@ -55,7 +54,7 @@ def logout(): def admin_homepage(): if not ( "user" in session - and session["user"] == config.get(ConfigParameter.WEB_USERNAME) + and session["user"] == app.config['CONFIG'].get(ConfigParameter.WEB_USERNAME) ): # TODO localization flash("Vous avez été déconnecté.") @@ -63,9 +62,9 @@ def admin_homepage(): comments = dao.find_not_published_comments() return render_template( - "admin_" + config.get(ConfigParameter.LANG) + ".html", + "admin_" + app.config['CONFIG'].get(ConfigParameter.LANG) + ".html", comments=comments, - baseurl=config.get(ConfigParameter.SITE_URL), + baseurl=app.config['CONFIG'].get(ConfigParameter.SITE_URL), ) @@ -77,7 +76,7 @@ def admin_action(): flash("Commentaire introuvable") elif request.form.get("action") == "APPROVE": dao.publish_comment(comment) - rss.generate() + app.config['RSS'].generate() # TODO localization flash("Commentaire publié") else: diff --git a/src/stacosys/run.py b/src/stacosys/run.py index 8e6f168..ae7b81b 100644 --- a/src/stacosys/run.py +++ b/src/stacosys/run.py @@ -9,55 +9,34 @@ import sys from stacosys.db import database from stacosys.interface import api, app, form from stacosys.interface.web import admin -from stacosys.service import config, mailer, rss -from stacosys.service.configuration import ConfigParameter +from stacosys.service.mail import Mailer +from stacosys.service.rssfeed import Rss +from stacosys.service.configuration import Config, ConfigParameter # configure logging -def configure_logging(level): - root_logger = logging.getLogger() - root_logger.setLevel(level) - handler = logging.StreamHandler() - handler.setLevel(level) - formatter = logging.Formatter("[%(asctime)s] %(name)s %(levelname)s %(message)s") - handler.setFormatter(formatter) - root_logger.addHandler(handler) - - -def stacosys_server(config_pathname): - # configure logging +def configure_logging() -> logging.Logger: + logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(name)s %(levelname)s %(message)s") logger = logging.getLogger(__name__) - configure_logging(logging.INFO) logging.getLogger("werkzeug").level = logging.WARNING + return logger - # check config file exists + +def load_and_validate_config(config_pathname: str, logger: logging.Logger) -> Config: if not os.path.isfile(config_pathname): logger.error("Configuration file '%s' not found.", config_pathname) - sys.exit(1) + raise FileNotFoundError(f"Configuration file '{config_pathname}' not found.") - # load and check config + config = Config() config.load(config_pathname) - is_config_ok, config_error = config.check() - if not is_config_ok: - logger.error("Invalid configuration '%s'", config_error) - sys.exit(1) - logger.info(config) - - # initialize database - database.configure(config.get(ConfigParameter.DB)) + if not config.check(): + raise ValueError(f"Invalid configuration '{config_pathname}'") + logger.info("Configuration loaded successfully.") + return config - logger.info("Start Stacosys application") - # generate RSS - rss.configure( - config.get(ConfigParameter.RSS_FILE), - config.get(ConfigParameter.SITE_NAME), - config.get(ConfigParameter.SITE_PROTO), - config.get(ConfigParameter.SITE_URL), - ) - rss.generate() - - # configure mailer +def configure_and_validate_mailer(config, logger): + mailer = Mailer() mailer.configure_smtp( config.get(ConfigParameter.SMTP_HOST), config.get_int(ConfigParameter.SMTP_PORT), @@ -68,10 +47,34 @@ def stacosys_server(config_pathname): if not mailer.check(): logger.error("Email configuration not working") sys.exit(1) + return mailer - logger.info("start interfaces %s %s %s", api, form, admin) - # start Flask +def configure_rss(config): + rss = Rss() + rss.configure( + config.get(ConfigParameter.RSS_FILE), + config.get(ConfigParameter.SITE_NAME), + config.get(ConfigParameter.SITE_PROTO), + config.get(ConfigParameter.SITE_URL), + ) + rss.generate() + return rss + + +def main(config_pathname): + logger = configure_logging() + config = load_and_validate_config(config_pathname, logger) + database.configure(config.get(ConfigParameter.DB)) + + logger.info("Start Stacosys application") + rss = configure_rss(config) + mailer = configure_and_validate_mailer(config, logger) + + logger.info("start interfaces %s %s %s", api, form, admin) + app.config['CONFIG'] = config + app.config['MAILER'] = mailer + app.config['RSS'] = rss app.run( host=config.get(ConfigParameter.HTTP_HOST), port=config.get_int(ConfigParameter.HTTP_PORT), @@ -84,4 +87,8 @@ if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("config", help="config path name") args = parser.parse_args() - stacosys_server(args.config) + try: + main(args.config) + except Exception as e: + logging.error(f"Failed to start application: {e}") + sys.exit(1) diff --git a/src/stacosys/service/__init__.py b/src/stacosys/service/__init__.py deleted file mode 100644 index 6fcc80a..0000000 --- a/src/stacosys/service/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from .configuration import Config -from .mail import Mailer -from .rssfeed import Rss - -config = Config() -mailer = Mailer() -rss = Rss()