From 4f641f24e6f3f1f365f8c4e09b89b1fce1ee3826 Mon Sep 17 00:00:00 2001 From: Ilona Date: Tue, 27 Aug 2024 02:06:22 +0200 Subject: [PATCH] Flask app minimal structure --- .gitignore | 15 ++++++++ app/__init__.py | 30 ++++++++++++++++ app/cli.py | 7 ++++ app/templates/base.j2 | 27 ++++++++++++++ app/utils/utils.py | 10 ++++++ app/views/__init__.py | 8 +++++ app/views/views.py | 9 +++++ autosco.py | 51 +++++++++++++++++++++++++++ config.py | 82 +++++++++++++++++++++++++++++++++++++++++++ version.py | 3 ++ 10 files changed, 242 insertions(+) create mode 100644 app/__init__.py create mode 100644 app/cli.py create mode 100644 app/templates/base.j2 create mode 100644 app/utils/utils.py create mode 100644 app/views/__init__.py create mode 100644 app/views/views.py create mode 100755 autosco.py create mode 100644 config.py create mode 100644 version.py diff --git a/.gitignore b/.gitignore index 5d381cc..02cdc69 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,18 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +# Mac OSX OS generated files +.DS_Store? +Thumbs.db +*.DS_Store + + +# VS Code +.vscode/ +*.code-workspace + +# Symlinks static ScoDoc +app/static/links/[0-9]*.* + +# Essais locaux +xp/ diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..fa80920 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,30 @@ +from flask import current_app, g, request +from flask import Flask + +from config import DevConfig + + +class ReverseProxied: + """Adaptateur wsgi qui nous permet d'avoir toutes les URL calculées en https + sauf quand on est en dev. + La variable HTTP_X_FORWARDED_PROTO est positionnée par notre config nginx""" + + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + scheme = environ.get("HTTP_X_FORWARDED_PROTO") + if scheme: + environ["wsgi.url_scheme"] = scheme # ou forcer à https ici ? + return self.app(environ, start_response) + + +def create_app(config_class=DevConfig): + app = Flask(__name__, static_url_path="/AutoSco/static", static_folder="static") + app.config.from_object(config_class) + app.wsgi_app = ReverseProxied(app.wsgi_app) + + from app.views import bp + + app.register_blueprint(bp) + return app diff --git a/app/cli.py b/app/cli.py new file mode 100644 index 0000000..25ae4d4 --- /dev/null +++ b/app/cli.py @@ -0,0 +1,7 @@ +# -*- coding: UTF-8 -* +import os +import click + + +def register(app): + pass diff --git a/app/templates/base.j2 b/app/templates/base.j2 new file mode 100644 index 0000000..71beceb --- /dev/null +++ b/app/templates/base.j2 @@ -0,0 +1,27 @@ +{%- block doc -%}{# Base de toutes les pages AutoSco #} + +{%- block html %} + + {%- block head %} + {% block title %}{{title|default}}{% endblock title %} + + {%- block metas %} + + {%- endblock metas %} + + {%- endblock head %} + + + {% block body -%} + {% block navbar %} + {%- endblock navbar %} + {% block content -%} + {%- endblock content %} + + {% block scripts %} + {%- endblock scripts %} + {%- endblock body %} + +{%- endblock html %} + +{% endblock doc -%} diff --git a/app/utils/utils.py b/app/utils/utils.py new file mode 100644 index 0000000..d0ed8fd --- /dev/null +++ b/app/utils/utils.py @@ -0,0 +1,10 @@ +"""AutoSco / utils.py +""" + +import os +import version + +# le répertoire static, lié à chaque release pour éviter les problèmes de caches +STATIC_DIR = ( + os.environ.get("SCRIPT_NAME", "") + "/AutoSco/static/links/" + version.VERSION +) diff --git a/app/views/__init__.py b/app/views/__init__.py new file mode 100644 index 0000000..2dce013 --- /dev/null +++ b/app/views/__init__.py @@ -0,0 +1,8 @@ +"""AutoSco Flask views""" + +from flask import Blueprint +from flask import g, current_app, request + +bp = Blueprint("autosco", __name__) + +from app.views import views diff --git a/app/views/views.py b/app/views/views.py new file mode 100644 index 0000000..3a51732 --- /dev/null +++ b/app/views/views.py @@ -0,0 +1,9 @@ +"""AutoSco / views +""" + +from app.views import bp + + +@bp.route("/") +def index(): + return "hello" diff --git a/autosco.py b/autosco.py new file mode 100755 index 0000000..c938aba --- /dev/null +++ b/autosco.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +"""Application Flask: AutoSco""" + +import os +from pprint import pprint as pp + +import click +import flask +from flask.cli import with_appcontext +from flask.templating import render_template + +import app as mapp +from app import create_app, cli +from app.utils import utils as scu + +from config import RunningConfig + +app = create_app(RunningConfig) +cli.register(app) + + +@app.context_processor +def inject_utils(): + "Make scu available in all Jinja templates" + # if modified, put the same in conftest.py#27 + return { + "DEBUG": flask.current_app.config["DEBUG"], + "scu": scu, + } + + +@app.shell_context_processor +def make_shell_context(): + import app as mapp # le package app + from app.utils import sco_utils as scu + + return { + "ctx": app.test_request_context(), + "current_app": flask.current_app, + "current_user": current_user, + "datetime": datetime, + "flask": flask, + "mapp": mapp, + "pp": pp, + "scu": scu, + } + + +if __name__ == "__main__": + port = os.environ.get("PORT", 5001) + app.run(debug=True, port=port) diff --git a/config.py b/config.py new file mode 100644 index 0000000..10b2b85 --- /dev/null +++ b/config.py @@ -0,0 +1,82 @@ +import os +import logging +from dotenv import load_dotenv + +BASEDIR = os.path.abspath(os.path.dirname(__file__)) +load_dotenv(os.path.join(BASEDIR, ".env")) + + +class Config: + """General configuration. Mostly loaded from environment via .env""" + + FLASK_ENV = None # # set in subclass + SECRET_KEY = os.environ.get("SECRET_KEY") or "90e01e751977d4276a4c70d98564b425e" + LOG_TO_STDOUT = os.environ.get("LOG_TO_STDOUT") + LOG_LEVEL = getattr(logging, os.environ.get("LOG_LEVEL", "INFO"), "INFO") + MAIL_SERVER = os.environ.get("MAIL_SERVER", "localhost") + LANGUAGES = ["fr", "en"] # unused for now + ADMIN_MAIL = os.environ.get("ADMIN_MAIL") + ADMIN_LOGIN = os.environ.get("ADMIN_LOGIN") or "admin" + ADMINS = [ADMIN_MAIL] + ERR_MAIL = os.environ.get("ERR_MAIL") + # Le "from" des mails émis. Attention: peut être remplacée par la préférence email_from_addr: + MAIL_FROM = os.environ.get("MAIL_FROM") or ("no-reply@" + MAIL_SERVER) + + AUTOSCO_DIR = os.environ.get("AUTOSCO_DIR", "/opt/autosco") + AUTOSCO_VAR_DIR = os.environ.get("AUTOSCO_VAR_DIR", "/opt/autosco-data") + AUTOSCO_LOG_FILE = os.path.join(AUTOSCO_VAR_DIR, "log", "autosco.log") + # evite confusion avec le log nginx scodoc_error.log: + AUTOSCO_ERR_FILE = os.path.join(AUTOSCO_VAR_DIR, "log", "autosco_exc.log") + # + MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # Flask uploads (16Mo, en ligne avec nginx) + # flask_json: + JSON_ADD_STATUS = False + JSON_USE_ENCODE_METHODS = True + JSON_DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z" # "%Y-%m-%dT%H:%M:%S" + + +class ProdConfig(Config): + "mode production, normalement derrière nginx/gunicorn" + + FLASK_ENV = "production" + DEBUG = False + TESTING = False + PREFERRED_URL_SCHEME = "https" + + +class DevConfig(Config): + "mode développement" + + FLASK_ENV = "development" + DEBUG = True + TESTING = False + SECRET_KEY = os.environ.get("DEV_SECRET_KEY") or "cc4fbec7d9a34eb69a7e3e710087d87a" + + +class TestConfig(DevConfig): + "Pour les tests unitaires" + + TESTING = True + DEBUG = False + SERVER_NAME = os.environ.get("AUTOSCO_TEST_SERVER_NAME") or "autotest.gr" + SECRET_KEY = os.environ.get("TEST_SECRET_KEY") or "c8ecff5db1592c308f563ff30e0f6bbc" + + +class TestAPIConfig(Config): + "Pour les tests de l'API" + + FLASK_ENV = "test_api" + TESTING = False + DEBUG = True + SECRET_KEY = os.environ.get("TEST_SECRET_KEY") or "d8ecff5db15946789Hhahbh88aja276" + + +mode = os.environ.get("FLASK_ENV", "production") +if mode == "production": + RunningConfig = ProdConfig +elif mode == "development": + RunningConfig = DevConfig +elif mode == "test": + RunningConfig = TestConfig +elif mode == "test_api": + RunningConfig = TestAPIConfig diff --git a/version.py b/version.py new file mode 100644 index 0000000..cb95558 --- /dev/null +++ b/version.py @@ -0,0 +1,3 @@ +VERSION = "0.0.0" + +NAME = "AutoSco"