haldis/app/app.py

183 lines
5.6 KiB
Python
Raw Normal View History

2020-01-24 15:38:03 +01:00
#!/usr/bin/env python3
2019-09-10 15:17:35 +02:00
"Main Haldis script"
2015-04-02 12:41:19 +02:00
import logging
2019-09-10 15:17:35 +02:00
from logging.handlers import TimedRotatingFileHandler
2019-09-08 01:58:21 +02:00
import typing
from datetime import datetime
from airbrake import Airbrake, AirbrakeHandler
from flask import Flask, render_template
2017-01-06 12:05:31 +01:00
from flask_bootstrap import Bootstrap, StaticCDN
2015-06-09 22:24:48 +02:00
from flask_debugtoolbar import DebugToolbarExtension
from flask_login import LoginManager
from flask_migrate import Migrate, MigrateCommand
from flask_oauthlib.client import OAuth, OAuthException
2019-09-03 13:56:13 +02:00
from flask_script import Manager, Server
2015-03-31 20:15:22 +02:00
2020-01-24 15:47:29 +01:00
import hlds
from admin import init_admin
from login import init_login
from models import db
from models.anonymous_user import AnonymouseUser
from utils import euro_string
from zeus import init_oauth
2019-09-08 01:58:21 +02:00
def create_app() -> Manager:
2019-09-10 15:17:35 +02:00
"Create the Haldis application"
app = Flask(__name__)
# Load the config file
2019-09-05 03:33:29 +02:00
app.config.from_object("config.Configuration")
2019-09-10 15:17:35 +02:00
app_manager = register_plugins(app)
add_handlers(app)
add_routes(app)
add_template_filters(app)
# TODO do we need to return and then run the manager?
2019-09-10 15:17:35 +02:00
return app_manager
2019-09-10 15:17:35 +02:00
def register_plugins(app: Flask) -> Manager:
"Register all the plugins to Haldis"
# pylint: disable=W0612
# Register Airbrake and enable the logrotation
if not app.debug:
2019-09-05 03:33:29 +02:00
timedFileHandler = TimedRotatingFileHandler(
app.config["LOGFILE"], when="midnight", backupCount=100
)
timedFileHandler.setLevel(logging.DEBUG)
2019-09-05 03:33:29 +02:00
loglogger = logging.getLogger("werkzeug")
loglogger.setLevel(logging.DEBUG)
loglogger.addHandler(timedFileHandler)
app.logger.addHandler(timedFileHandler)
2019-09-05 03:33:29 +02:00
airbrakelogger = logging.getLogger("airbrake")
# Airbrake
2019-09-10 15:17:35 +02:00
airbrake = Airbrake(project_id=app.config["AIRBRAKE_ID"],
api_key=app.config["AIRBRAKE_KEY"])
# ugly hack to make this work for out errbit
airbrake._api_url = "http://errbit.awesomepeople.tv/api/v3/projects/{}/notices".format( # pylint: disable=W0212
2019-09-05 03:33:29 +02:00
airbrake.project_id
)
airbrakelogger.addHandler(AirbrakeHandler(airbrake=airbrake))
app.logger.addHandler(AirbrakeHandler(airbrake=airbrake))
# Initialize SQLAlchemy
db.init_app(app)
2020-01-24 15:47:29 +01:00
# Load locations
locations = hlds.load_all()
# Initialize Flask-Migrate
migrate = Migrate(app, db)
2019-09-10 15:17:35 +02:00
app_manager = Manager(app)
app_manager.add_command("db", MigrateCommand)
app_manager.add_command("runserver", Server(port=8000))
# Add admin interface
init_admin(app, db)
# Init login manager
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.anonymous_user = AnonymouseUser
init_login(app)
# Add oauth
zeus = init_oauth(app)
app.zeus = zeus
# Load the bootstrap local cdn
Bootstrap(app)
2019-09-05 03:33:29 +02:00
app.config["BOOTSTRAP_SERVE_LOCAL"] = True
# use our own bootstrap theme
2019-09-05 03:33:29 +02:00
app.extensions["bootstrap"]["cdns"]["bootstrap"] = StaticCDN()
# Load the flask debug toolbar
toolbar = DebugToolbarExtension(app)
2019-09-11 16:43:42 +02:00
# Make cookies more secure
app.config.update(
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
)
if not app.debug:
app.config.update(SESSION_COOKIE_SECURE=True)
2019-09-10 15:17:35 +02:00
return app_manager
2019-09-08 01:58:21 +02:00
def add_handlers(app: Flask) -> None:
2019-09-10 15:17:35 +02:00
"Add handlers for 4xx error codes"
# pylint: disable=W0612,W0613
@app.errorhandler(404)
2019-09-08 01:58:21 +02:00
def handle404(e) -> typing.Tuple[str, int]:
2019-09-05 03:33:29 +02:00
return render_template("errors/404.html"), 404
2015-06-09 16:47:11 +02:00
@app.errorhandler(401)
2019-09-08 01:58:21 +02:00
def handle401(e) -> typing.Tuple[str, int]:
2019-09-05 03:33:29 +02:00
return render_template("errors/401.html"), 401
2015-03-31 20:15:22 +02:00
2019-09-08 01:58:21 +02:00
def add_routes(application: Flask) -> None:
2019-09-10 15:17:35 +02:00
"Add all routes to Haldis"
# import views # TODO convert to blueprint
# import views.stats # TODO convert to blueprint
2015-03-31 20:15:22 +02:00
from views.order import order_bp
from views.general import general_bp
from views.stats import stats_blueprint
from views.debug import debug_bp
from login import auth_bp
from zeus import oauth_bp
2015-03-31 20:15:22 +02:00
2019-09-05 03:33:29 +02:00
application.register_blueprint(general_bp, url_prefix="/")
application.register_blueprint(order_bp, url_prefix="/order")
application.register_blueprint(stats_blueprint, url_prefix="/stats")
application.register_blueprint(auth_bp, url_prefix="/")
application.register_blueprint(oauth_bp, url_prefix="/")
2015-06-09 22:24:48 +02:00
if application.debug:
2019-09-05 03:33:29 +02:00
application.register_blueprint(debug_bp, url_prefix="/debug")
2015-03-31 16:29:28 +02:00
2019-09-08 01:58:21 +02:00
def add_template_filters(app: Flask) -> None:
2019-09-10 15:17:35 +02:00
"Add functions which can be used in the templates"
# pylint: disable=W0612
2019-09-05 03:33:29 +02:00
@app.template_filter("countdown")
2019-09-10 15:17:35 +02:00
def countdown(value, only_positive: bool = True,
show_text: bool = True) -> str:
"A function which returns time until the order is done"
delta = value - datetime.now()
if delta.total_seconds() < 0 and only_positive:
return "closed"
hours, remainder = divmod(delta.seconds, 3600)
minutes, seconds = divmod(remainder, 60)
2019-09-05 03:33:29 +02:00
time = "%02d:%02d:%02d" % (hours, minutes, seconds)
if show_text:
return f"{time} left"
return time
2015-06-09 16:47:11 +02:00
2019-09-05 03:33:29 +02:00
@app.template_filter("year")
2019-09-10 15:17:35 +02:00
def current_year(value: typing.Any) -> str: # pylint: disable=W0613
"A function which returns the current year"
return str(datetime.now().year)
2015-06-09 16:47:11 +02:00
2019-09-05 03:33:29 +02:00
@app.template_filter("euro")
def euro(value: int) -> str:
2019-09-10 15:17:35 +02:00
"A function which converts a value to its euro_string"
2019-09-13 16:51:38 +02:00
return euro_string(value)
2015-06-09 16:47:11 +02:00
# For usage when you directly call the script with python
2019-09-05 03:33:29 +02:00
if __name__ == "__main__":
2019-09-03 13:56:13 +02:00
manager = create_app()
manager.run()