Select Git revision
-
Lukáš Ondráček authoredLukáš Ondráček authored
__init__.py 5.14 KiB
import datetime
from mo import util_format
import dateutil.tz
from flask import Flask, request, g, session
import flask.logging
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
import locale
import logging
import os
import werkzeug.exceptions
import mo
import mo.config as config
import mo.db as db
import mo.jobs
import mo.users
import mo.util
from mo.util import logger
# Flask interpretuje relativní cesty všelijak, tak mu vyrobíme absolutní
mo.config.DATA_DIR = os.path.abspath(mo.config.DATA_DIR)
static_dir = os.path.abspath('static')
# Aplikační objekt
app = Flask(__name__, instance_path=mo.config.DATA_DIR, static_folder=static_dir)
app.config.from_object(config)
app.jinja_options['extensions'].append('jinja2.ext.do')
app.jinja_env.lstrip_blocks = True
app.jinja_env.trim_blocks = True
db.flask_db = SQLAlchemy(app, metadata=db.metadata)
Bootstrap(app) # make bootstrap libs accessible for the app
# Budeme používat české locale
locale.setlocale(locale.LC_COLLATE, 'cs_CZ.UTF-8')
# Naše filtry pro Jinju
app.jinja_env.filters.update(timeformat=util_format.timeformat)
app.jinja_env.filters.update(inflected=util_format.inflect_number)
app.jinja_env.filters.update(timedelta=util_format.timedelta)
app.jinja_env.filters.update(time_and_timedelta=util_format.time_and_timedelta)
# Incializace logování
def setup_logging():
# Logování v Pythonu je vymyšlené hezky, ale bohužel spousta modulů má tendenci
# konfigurovat si u svých loggerů náhodné handlery. Pokud chceme, aby bylo logování
# aspoň trochu jednotné, musíme jim to trochu předrátovat.
# Nastavíme root logger, aby logoval po našem do flaskového logu
log_handler = flask.logging.default_handler
log_formatter = logging.Formatter(fmt='%(asctime)-15s.%(msecs)03d %(levelname)-5.5s [%(process)s] (%(name)s) %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
log_handler.setFormatter(log_formatter)
root_logger = logging.getLogger()
root_logger.addHandler(log_handler)
# app.logger se jmenuje "mo.web" a propaguje se do root loggeru,
# takže nechceme, aby měl svůj handler.
app.logger.removeHandler(log_handler)
app.logger.setLevel(logging.DEBUG)
# sqlalchemy má logger, ke kterému si při prvním vypsání hlášky přidá handler,
# není-li tam zatím žádný. Tak přidáme dummy handler. Vše se propaguje do root loggeru.
sqla_logger = logging.getLogger('sqlalchemy.engine.base.Engine')
sqla_logger.addHandler(logging.NullHandler())
# werkzeug má vlastní handler s vlastním formátem hlášek, který už obsahuje timestamp,
# takže vypneme propagování
wz_logger = logging.getLogger('werkzeug')
wz_logger.propagate = False
setup_logging()
# Inicializace požadavků a nucená autorizace
class NeedLoginError(werkzeug.exceptions.Forbidden):
description = 'Need to log in'
def need_login():
if not g.user:
raise NeedLoginError()
def init_request():
if 'uid' in session:
user = mo.users.user_by_uid(session['uid'])
if not user:
# Uživatel mezitím přestal existovat
app.logging.error('Zrušena session pro neexistujícího uživatele uid=%s', session['uid'])
return mo.web.main.logout()
else:
user = None
g.user = user
mo.now = mo.util.get_now()
g.now = mo.now # for templates
mo.util.current_log_user = user
# K některým podstromům je nutné mít speciální oprávnění
# XXX: Když celá aplikace běží v adresáři, request.path je relativní ke kořeni aplikace, ne celého webu
path = request.path
if path.startswith('/org/'):
if not user:
raise NeedLoginError()
if not (user.is_org or user.is_admin):
raise werkzeug.exceptions.Forbidden()
elif path.startswith('/user/'):
if not user:
raise NeedLoginError()
app.before_request(init_request)
### UWSGI glue ###
try:
import uwsgi
from uwsgidecorators import timer, signal
# Čas od času se probudíme a projdeme joby pro případ, že by se ztratil signál.
# Také při tom expirujeme zastaralé joby.
@timer(config.JOB_GC_PERIOD, target='mule')
def mule_timer(signum):
app.logger.debug('Mule: Timer tick')
with app.app_context():
mo.now = mo.util.get_now()
mo.jobs.process_jobs()
# Obykle při vložení jobu dostaneme signál.
@signal(42, target='mule')
def mule_signal(signum):
app.logger.debug('Mule: Přijat signál')
with app.app_context():
mo.now = mo.util.get_now()
mo.jobs.process_jobs()
def wake_up_mule():
app.logger.debug('Mule: Posíláme signál')
uwsgi.signal(42)
mo.jobs.send_notify = wake_up_mule
except ImportError:
app.logger.warn('Nenalezeno UWSGI, takže automatické notifikace nepoběží.')
# Většina webu je v samostatných modulech
import mo.web.auth
import mo.web.menu
import mo.web.misc
import mo.web.org
import mo.web.org_contest
import mo.web.org_jobs
import mo.web.org_place
import mo.web.org_round
import mo.web.org_users
import mo.web.user