Skip to content
Snippets Groups Projects
Select Git revision
  • 4daa7ed48f9e25e3ff33540b71c7017cf45c663f
  • master default protected
2 results

Makefile

Blame
  • __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