Flask app minimal structure
This commit is contained in:
parent
c2f4abf631
commit
4f641f24e6
15
.gitignore
vendored
15
.gitignore
vendored
@ -160,3 +160,18 @@ cython_debug/
|
|||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.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/
|
||||||
|
30
app/__init__.py
Normal file
30
app/__init__.py
Normal file
@ -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
|
7
app/cli.py
Normal file
7
app/cli.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# -*- coding: UTF-8 -*
|
||||||
|
import os
|
||||||
|
import click
|
||||||
|
|
||||||
|
|
||||||
|
def register(app):
|
||||||
|
pass
|
27
app/templates/base.j2
Normal file
27
app/templates/base.j2
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{%- block doc -%}<!DOCTYPE html>{# Base de toutes les pages AutoSco #}
|
||||||
|
<html{% block html_attribs %}{% endblock html_attribs %}>
|
||||||
|
{%- block html %}
|
||||||
|
<head>
|
||||||
|
{%- block head %}
|
||||||
|
<title>{% block title %}{{title|default}}{% endblock title %}</title>
|
||||||
|
|
||||||
|
{%- block metas %}
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
{%- endblock metas %}
|
||||||
|
|
||||||
|
{%- endblock head %}
|
||||||
|
</head>
|
||||||
|
<body{% block body_attribs %}{% endblock body_attribs %}>
|
||||||
|
{% block body -%}
|
||||||
|
{% block navbar %}
|
||||||
|
{%- endblock navbar %}
|
||||||
|
{% block content -%}
|
||||||
|
{%- endblock content %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{%- endblock scripts %}
|
||||||
|
{%- endblock body %}
|
||||||
|
</body>
|
||||||
|
{%- endblock html %}
|
||||||
|
</html>
|
||||||
|
{% endblock doc -%}
|
10
app/utils/utils.py
Normal file
10
app/utils/utils.py
Normal file
@ -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
|
||||||
|
)
|
8
app/views/__init__.py
Normal file
8
app/views/__init__.py
Normal file
@ -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
|
9
app/views/views.py
Normal file
9
app/views/views.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""AutoSco / views
|
||||||
|
"""
|
||||||
|
|
||||||
|
from app.views import bp
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/")
|
||||||
|
def index():
|
||||||
|
return "hello"
|
51
autosco.py
Executable file
51
autosco.py
Executable file
@ -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)
|
82
config.py
Normal file
82
config.py
Normal file
@ -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
|
3
version.py
Normal file
3
version.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
VERSION = "0.0.0"
|
||||||
|
|
||||||
|
NAME = "AutoSco"
|
Loading…
Reference in New Issue
Block a user