From 4749626ca0494601a32335d03cc998e03ed80858 Mon Sep 17 00:00:00 2001 From: Mo8it Date: Mon, 8 Aug 2022 18:01:33 +0200 Subject: [PATCH] Use configparser --- .gitignore | 13 ++--- advlabdb/__init__.py | 51 ++--------------- advlabdb/adminModelViews.py | 2 +- advlabdb/advlabdb_independent_funs.py | 10 ---- advlabdb/assistantModelViews.py | 2 +- advlabdb/config.py | 57 +++++++++++++++++++ .../{customClasses.py => custom_classes.py} | 0 settings_example.ini | 4 ++ 8 files changed, 74 insertions(+), 65 deletions(-) create mode 100644 advlabdb/config.py rename advlabdb/{customClasses.py => custom_classes.py} (100%) create mode 100644 settings_example.ini diff --git a/.gitignore b/.gitignore index 2e78f6c..7d4bd39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ -# Do not commit the environment variables file with the secret key and password salt! -.env +# Do not commit/publish the secrets file with the secret key and password salt! +secrets.ini + +# Own settings +settings.ini # Python __pycache__ @@ -8,14 +11,8 @@ __pycache__ # Database db/ -# Development -.flaskenv - # Poetry .venv/ -# Nginx -advlabdb.conf - # Flask-Migrate migrations/ diff --git a/advlabdb/__init__.py b/advlabdb/__init__.py index b3ee1bb..1b7605b 100644 --- a/advlabdb/__init__.py +++ b/advlabdb/__init__.py @@ -1,82 +1,43 @@ -from os import environ, makedirs - from flask import Flask from flask_admin import Admin from flask_security import Security, SQLAlchemyUserDatastore from flask_security.models import fsqla_v2 as fsqla from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate - -from dotenv import load_dotenv - -from .advlabdb_independent_funs import parse_bool - - -def set_from_env(app, var): - app.config[var] = environ[var] - - -load_dotenv(".env") +from .config import set_config app = Flask(__name__) -set_from_env(app, "SECRET_KEY") +set_config(app) + # Setup Flask-SQLAlchemy -app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///../{environ['RELATIVE_DB_DIR']}/advlab.db" -makedirs(environ["RELATIVE_DB_DIR"], exist_ok=True) - -app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False - db = SQLAlchemy(app) - fsqla.FsModels.set_db_info(db) # Setup Flask-Migrate migrate = Migrate(app, db) -from . import customClasses - # Setup Flask-Admin -app.config["FLASK_ADMIN_FLUID_LAYOUT"] = True +from .custom_classes import SecureAdminIndexView, SecureAssistantIndexView adminSpace = Admin( app, name="Admin@AdvLabDB", url="/admin", template_mode="bootstrap3", - index_view=customClasses.SecureAdminIndexView(name="Home", url="/admin", endpoint="admin"), + index_view=SecureAdminIndexView(name="Home", url="/admin", endpoint="admin"), ) assistantSpace = Admin( app, name="Assistant@AdvLabDB", url="/assistant", template_mode="bootstrap3", - index_view=customClasses.SecureAssistantIndexView(name="Home", url="/assistant", endpoint="assistant"), + index_view=SecureAssistantIndexView(name="Home", url="/assistant", endpoint="assistant"), ) from . import models -# Setup Flask-Security -# Enable features -app.config["SECURITY_TRACKABLE"] = True - -# Explicitly disable features -app.config["SECURITY_CONFIRMABLE"] = False -app.config["SECURITY_REGISTERABLE"] = False -app.config["SECURITY_RECOVERABLE"] = False -app.config["SECURITY_PASSWORDLESS"] = False -app.config["SECURITY_CHANGEABLE"] = False -app.config["SECURITY_TWO_FACTOR"] = False -app.config["SECURITY_UNIFIED_SIGNIN"] = False - -app.config["SECURITY_EMAIL_VALIDATOR_ARGS"] = { - "check_deliverability": parse_bool(environ["CHECK_EMAIL_DELIVERABILITY"]) -} -set_from_env(app, "SECURITY_PASSWORD_SALT") -app.config["SECURITY_PASSWORD_LENGTH_MIN"] = 15 -# TODO: app.config["SECURITY_LOGIN_USER_TEMPLATE"] = - user_datastore = SQLAlchemyUserDatastore(db, models.User, models.Role) Security(app, user_datastore) diff --git a/advlabdb/adminModelViews.py b/advlabdb/adminModelViews.py index f9ed58a..4942f8f 100644 --- a/advlabdb/adminModelViews.py +++ b/advlabdb/adminModelViews.py @@ -56,7 +56,7 @@ from .advlabdb_independent_funs import ( flashRandomPassword, str_without_semester_formatter, ) -from .customClasses import SecureAdminBaseView, SecureAdminModelView +from .custom_classes import SecureAdminBaseView, SecureAdminModelView from .database_import import importFromFile from .exceptions import ModelViewException from .model_dependent_funs import ( diff --git a/advlabdb/advlabdb_independent_funs.py b/advlabdb/advlabdb_independent_funs.py index 3fd2c70..a52285c 100644 --- a/advlabdb/advlabdb_independent_funs.py +++ b/advlabdb/advlabdb_independent_funs.py @@ -10,16 +10,6 @@ def flashRandomPassword(email: str, password: str): flash(f"New random password for email {email}: {password}", category="warning") -def parse_bool(str): - str_lower = str.lower() - if str_lower == "false": - return False - elif str_lower == "true": - return True - else: - raise ValueError(f'Can not parse a bool from "{str}"') - - def deep_getattr(object, composed_name): names = composed_name.split(".") attr = getattr(object, names[0]) diff --git a/advlabdb/assistantModelViews.py b/advlabdb/assistantModelViews.py index 99368af..29aacf7 100644 --- a/advlabdb/assistantModelViews.py +++ b/advlabdb/assistantModelViews.py @@ -11,7 +11,7 @@ from .advlabdb_independent_funs import ( flashRandomPassword, str_formatter, ) -from .customClasses import SecureAssistantBaseView, SecureAssistantModelView +from .custom_classes import SecureAssistantBaseView, SecureAssistantModelView from .exceptions import ModelViewException from .forms import assistant_group_experiment_form_factory from .model_dependent_funs import ( diff --git a/advlabdb/config.py b/advlabdb/config.py new file mode 100644 index 0000000..7d75d66 --- /dev/null +++ b/advlabdb/config.py @@ -0,0 +1,57 @@ +import sys +from configparser import ConfigParser +from pathlib import Path + + +def load_config(*files): + config = ConfigParser() + + for file in files: + file = Path(file) + + if not file.is_file(): + app.logger.critical(str(file) + " is missing") + sys.exit(1) + + config.read(file) + + return config + + +def set_config(app): + config = load_config("secrets.ini", "settings.ini") + secrets = config["Secrets"] + settings = config["Settings"] + + app.config["SECRET_KEY"] = secrets["SECRET_KEY"] + + # SQLALCHEMY + db_file = Path(settings["SQLITE_DB_PATH"]) + db_file.parent.mkdir(parents=True, exist_ok=True) + app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{db_file}" + + app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + + # Flask-Admin + app.config["FLASK_ADMIN_FLUID_LAYOUT"] = True + + # Flask-Security + # Enable features + app.config["SECURITY_TRACKABLE"] = True + + # Explicitly disable features + app.config["SECURITY_CONFIRMABLE"] = False + app.config["SECURITY_REGISTERABLE"] = False + app.config["SECURITY_RECOVERABLE"] = False + app.config["SECURITY_PASSWORDLESS"] = False + app.config["SECURITY_CHANGEABLE"] = False + app.config["SECURITY_TWO_FACTOR"] = False + app.config["SECURITY_UNIFIED_SIGNIN"] = False + + check_email_deliverability = settings.getboolean("CHECK_EMAIL_DELIVERABILITY", True) + app.config["SECURITY_EMAIL_VALIDATOR_ARGS"] = { + "check_deliverability": check_email_deliverability, + } + app.config["SECURITY_PASSWORD_SALT"] = secrets["SECURITY_PASSWORD_SALT"] + app.config["SECURITY_PASSWORD_LENGTH_MIN"] = settings.getint(SECURITY_PASSWORD_LENGTH_MIN, 15) + # TODO: app.config["SECURITY_LOGIN_USER_TEMPLATE"] = diff --git a/advlabdb/customClasses.py b/advlabdb/custom_classes.py similarity index 100% rename from advlabdb/customClasses.py rename to advlabdb/custom_classes.py diff --git a/settings_example.ini b/settings_example.ini new file mode 100644 index 0000000..47f767e --- /dev/null +++ b/settings_example.ini @@ -0,0 +1,4 @@ +[Settings] +SQLITE_DB_PATH = "../db/advlab.db" +CHECK_EMAIL_DELIVERABILITY = True +SECURITY_PASSWORD_LENGTH_MIN = 15