<commit_before># -*- coding: utf-8 -*-
## This file is part of Invenio.
## Copyright (C) 2011, 2012 CERN.
##
## Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

"""
Invenio -> Flask adapter
"""

import os
import hashlib
from os.path import join, exists, getmtime, splitext
from pprint import pformat
from logging.handlers import RotatingFileHandler
from logging import Formatter
from flask import Blueprint, Flask, logging, session, request, g, \
                url_for, current_app, Response, render_template
from jinja2 import FileSystemLoader, MemcachedBytecodeCache
from werkzeug.routing import BuildError, NotFound, RequestRedirect

from invenio.sqlalchemyutils import db
from invenio import config
from invenio.errorlib import register_exception
from invenio.config import CFG_PYLIBDIR, \
    CFG_WEBSESSION_EXPIRY_LIMIT_REMEMBER, \
    CFG_BIBDOCFILE_USE_XSENDFILE, \
    CFG_LOGDIR, CFG_SITE_LANG, CFG_WEBDIR, \
    CFG_ETCDIR, CFG_DEVEL_SITE, \
    CFG_FLASK_CACHE_TYPE
from invenio.websession_config import CFG_WEBSESSION_COOKIE_NAME, CFG_WEBSESSION_ONE_DAY

def create_invenio_flask_app():
    """
    This prepare wsgi Invenio application based on Flask.
    """

    ## The Flask application instance
    _app = Flask(__name__,
        static_url_path='/', ## We assume anything under '/' which is static to be handled directly by Apache
        static_folder=CFG_WEBDIR)

    ## Let's initialize database.
    db.init_invenio()
    db.init_cfg(_app)
    # Register Flask application in flask-sqlalchemy extension
    db.init_app(_app)


    from invenio.pluginutils import PluginContainer, create_enhanced_plugin_builder
    from invenio.session_flask import InvenioSessionInterface
#from flaskext.login import LoginManager
    from invenio.webuser_flask import InvenioLoginManager
    from invenio.messages import wash_language, gettext_set_language, language_list_long, is_language_rtl
    from invenio.dateutils import convert_datetext_to_dategui
    from invenio.urlutils import create_url
    from invenio.cache import cache
#from invenio.webuser import collect_user_info
    from invenio.jinja2utils import CollectionExtension
    from invenio.webmessage_mailutils import email_quoted_txt2html
    from flask.ext.assets import Environment, Bundle
    from invenio.webinterface_handler_flask_utils import unicodifier
    from flaskext.gravatar import Gravatar
    from werkzeug.wrappers import BaseResponse
    from werkzeug.exceptions import HTTPException

    from invenio.webinterface_handler_wsgi import \
                application as legacy_application

    class LegacyAppMiddleware(object):
        def __init__(self, app):
            self.app = app

        def __call__(self, environ, start_response):
            with self.app.request_context(environ):
                g.start_response = start_response
                try:
                    response = self.app.full_dispatch_request()
                except Exception, e:
                    response = self.app.make_response(self.app.handle_exception(e))
                    #raise
                    #register_exception(alert_admin=True)
                return response(environ, start_response)

    _app.wsgi_app = LegacyAppMiddleware(_app)

    @_app.errorhandler(404)
    def page_not_found(error):
        try:
            response = legacy_application(request.environ, g.start_response)
            if not isinstance(response, BaseResponse):
                response = str(response) #current_app.make_response(response)
            return response
        except HTTPException, e:
            return render_template("404.html"), 404

    if CFG_FLASK_CACHE_TYPE not in [None, 'null']:
        _app.jinja_options = dict(_app.jinja_options,
            auto_reload=False,
            cache_size=-1,
            bytecode_cache=MemcachedBytecodeCache(
                                cache, prefix="jinja::",
                                timeout=3600))


    ## Let's customize the template loader to first look into
    ## /opt/invenio/etc-local/templates and then into /opt/invenio/etc/templates
    _app.jinja_loader = FileSystemLoader([join(CFG_ETCDIR + '-local', 'templates'), join(CFG_ETCDIR, 'templates')])

    ## Let's attach our session handling (which is bridging with the native Invenio session handling
    _app.session_interface = InvenioSessionInterface()

    ## Let's load the whole invenio.config into Flask :-) ...
    _app.config.from_object(config)

    ## ... and map certain common parameters
    _app.config["SECRET_KEY"] = 'Inv3n10'
    _app.config['SESSION_COOKIE_NAME'] = CFG_WEBSESSION_COOKIE_NAME
    _app.config['PERMANENT_SESSION_LIFETIME'] = CFG_WEBSESSION_EXPIRY_LIMIT_REMEMBER * CFG_WEBSESSION_ONE_DAY
    _app.config['USE_X_SENDFILE'] = CFG_BIBDOCFILE_USE_XSENDFILE
    _app.config['DEBUG'] = False #CFG_DEVEL_SITE
    _app.debug = False #True #CFG_DEVEL_SITE
    _app.config['CFG_LANGUAGE_LIST_LONG'] = [(lang, longname.decode('utf-8')) for (lang, longname) in language_list_long()]

    ## Invenio is all using str objects. Let's change them to unicode
    _app.config.update(unicodifier(dict(_app.config)))

    ## Cache
    _app.config['CACHE_TYPE'] = CFG_FLASK_CACHE_TYPE
    cache.init_app(_app)

    _flask_log_handler = RotatingFileHandler(os.path.join(CFG_LOGDIR, 'flask.log'))
    _flask_log_handler.setFormatter(Formatter(
        '%(asctime)s %(levelname)s: %(message)s '
        '[in %(pathname)s:%(lineno)d]'
    ))
    _app.logger.addHandler(_flask_log_handler)

    # Let's create login manager.
    _login_manager = InvenioLoginManager()
    _login_manager.login_view = 'youraccount.login'
    _login_manager.setup_app(_app)

    # Let's create main menu.
    class Menu(object):
        def __init__(self, id='', title='', url='', order=None, children=None,
                     display=lambda:True):
            self.id = id
            self.title = title
            self.url = url
            self.children = children or {}
            self.order = order or 100
            self.display = display

    # Let's create assets environment.
    _assets = Environment(_app)
    _assets.debug = True #config.CFG_DEVEL_SITE == 1
    _assets.directory = config.CFG_WEBDIR

    _app.jinja_env.extend(new_bundle=lambda tag, collection: \
        Bundle(output="%s/invenio-%s.%s" % \
               (tag, hash('|'.join(collection)), tag),
               *collection))
    _app.jinja_env.add_extension(CollectionExtension)
    _app.jinja_env.add_extension('jinja2.ext.do')

    # Let's create Gravatar bridge.
    _gravatar = Gravatar(_app,
                    size=100,
                    rating='g',
                    default='retro',
                    force_default=False,
                    force_lower=False)

    @_login_manager.user_loader
    def _load_user(uid):
        """
        Function should not raise an exception if uid is not valid
        or User was not found in database.
        """
        try:
            from invenio.webuser_flask import UserInfo, current_user
            try:
                _app.logger.info("==== %s ====" % str(type(current_user._get_current_object())))
                #return current_user._get_current_object()
            except:
                _app.logger.info("==== CREATING NEW UserInfo OBJECT ====")
            return UserInfo()
        except:
            return None

    @_app.before_request
    def _populate_user_info():
        """
        Before every request being handled, let's compute the user_info dictionary
        which is used everywhere in Invenio to describe a user.

        This user_info dictionary is also stored in the session (under the 'user_info'
        key) and in the Flask global variable (under the 'user_info' attribute).
        """
        #from invenio.webuser_flask import UserInfo
        #g.user_info = UserInfo(session)
        pass

    @_app.before_request
    def _guess_language():
        """
        Before every request being handled, let's compute the language needed to
        return the answer to the client.

        This information will then be available in the session['ln'] and in g.ln.

        Additionally under g._ an already configured internationalization function
        will be available (configured to return unicode objects).
        """
        required_ln = None
        try:
            values = request.values
        except:
            values = {}
        if "ln" in values:
            ## If ln is specified explictly as a GET or POST argument
            ## let's take it!
            passed_ln = str(values["ln"])
            required_ln = wash_language(passed_ln)
            if passed_ln != required_ln:
                ## But only if it was a valid language
                required_ln = None
        if required_ln:
            ## Ok it was. We store it in the session.
            session["ln"] = required_ln
        if not "ln" in session:
            ## If there is no language saved into the session...
            if "user_info" in session and session["user_info"].get("language"):
                ## ... and the user is logged in, we try to take it from its
                ## settings.
                session["ln"] = session["user_info"]["language"]
            else:
                ## Otherwise we try to guess it from its request headers
                for value, quality in request.accept_languages:
                    value = str(value)
                    ln = wash_language(value)
                    if ln == value or ln[:2] == value[:2]:
                        session["ln"] = ln
                        break
                else:
                    ## Too bad! We stick to the default :-)
                    session["ln"] = CFG_SITE_LANG
        ## Well, let's make it global now
        g.ln = session["ln"]
        g._ = gettext_set_language(g.ln, use_unicode=True)

    @_app.template_filter('quoted_txt2html')
    def _quoted_txt2html(*args, **kwargs):
        return email_quoted_txt2html(*args, **kwargs)

    @_app.template_filter('invenio_format_date')
    def _format_date(date):
        """
        This is a special Jinja2 filter that will call convert_datetext_to_dategui
        to print a human friendly date.
        """
        return convert_datetext_to_dategui(date, g.ln).decode('utf-8')

    @_app.template_filter('invenio_url_args')
    def _url_args(d, append=u'?', filter=[]):
        from jinja2.utils import escape
        rv = append + u'&'.join(
            u'%s=%s' % (escape(key), escape(value))
            for key, value in d.iteritems(True)
            if value is not None and key not in filter
            # and not isinstance(value, Undefined)
        )
        return rv

    @_app.context_processor
    def _inject_utils():
        """
        This will add some more variables and functions to the Jinja2 to execution
        context. In particular it will add:

        - `url_for`: an Invenio specific wrapper of Flask url_for, that will let you
                     obtain URLs for non Flask-native handlers (i.e. not yet ported
                     Invenio URLs)
        - `breadcrumbs`: this will be a list of three-elements tuples, containing<commit_msg>WebStyle: invenio_format_date jinja filter fix<commit_after># -*- coding: utf-8 -*-
## This file is part of Invenio.
## Copyright (C) 2011, 2012 CERN.
##
## Invenio is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## Invenio is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Invenio; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

"""
Invenio -> Flask adapter
"""

import os
import hashlib
from os.path import join, exists, getmtime, splitext
from pprint import pformat
from datetime import datetime
from logging.handlers import RotatingFileHandler
from logging import Formatter
from flask import Blueprint, Flask, logging, session, request, g, \
                url_for, current_app, Response, render_template
from jinja2 import FileSystemLoader, MemcachedBytecodeCache
from werkzeug.routing import BuildError, NotFound, RequestRedirect

from invenio.sqlalchemyutils import db
from invenio import config
from invenio.errorlib import register_exception
from invenio.config import CFG_PYLIBDIR, \
    CFG_WEBSESSION_EXPIRY_LIMIT_REMEMBER, \
    CFG_BIBDOCFILE_USE_XSENDFILE, \
    CFG_LOGDIR, CFG_SITE_LANG, CFG_WEBDIR, \
    CFG_ETCDIR, CFG_DEVEL_SITE, \
    CFG_FLASK_CACHE_TYPE
from invenio.websession_config import CFG_WEBSESSION_COOKIE_NAME, CFG_WEBSESSION_ONE_DAY

def create_invenio_flask_app():
    """
    This prepare wsgi Invenio application based on Flask.
    """

    ## The Flask application instance
    _app = Flask(__name__,
        static_url_path='/', ## We assume anything under '/' which is static to be handled directly by Apache
        static_folder=CFG_WEBDIR)

    ## Let's initialize database.
    db.init_invenio()
    db.init_cfg(_app)
    # Register Flask application in flask-sqlalchemy extension
    db.init_app(_app)


    from invenio.pluginutils import PluginContainer, create_enhanced_plugin_builder
    from invenio.session_flask import InvenioSessionInterface
#from flaskext.login import LoginManager
    from invenio.webuser_flask import InvenioLoginManager
    from invenio.messages import wash_language, gettext_set_language, language_list_long, is_language_rtl
    from invenio.dateutils import convert_datetext_to_dategui, \
                                  convert_datestruct_to_dategui
    from invenio.urlutils import create_url
    from invenio.cache import cache
#from invenio.webuser import collect_user_info
    from invenio.jinja2utils import CollectionExtension
    from invenio.webmessage_mailutils import email_quoted_txt2html
    from flask.ext.assets import Environment, Bundle
    from invenio.webinterface_handler_flask_utils import unicodifier
    from flaskext.gravatar import Gravatar
    from werkzeug.wrappers import BaseResponse
    from werkzeug.exceptions import HTTPException

    from invenio.webinterface_handler_wsgi import \
                application as legacy_application

    class LegacyAppMiddleware(object):
        def __init__(self, app):
            self.app = app

        def __call__(self, environ, start_response):
            with self.app.request_context(environ):
                g.start_response = start_response
                try:
                    response = self.app.full_dispatch_request()
                except Exception, e:
                    response = self.app.make_response(self.app.handle_exception(e))
                    #raise
                    #register_exception(alert_admin=True)
                return response(environ, start_response)

    _app.wsgi_app = LegacyAppMiddleware(_app)

    @_app.errorhandler(404)
    def page_not_found(error):
        try:
            response = legacy_application(request.environ, g.start_response)
            if not isinstance(response, BaseResponse):
                response = str(response) #current_app.make_response(response)
            return response
        except HTTPException, e:
            return render_template("404.html"), 404

    if CFG_FLASK_CACHE_TYPE not in [None, 'null']:
        _app.jinja_options = dict(_app.jinja_options,
            auto_reload=False,
            cache_size=-1,
            bytecode_cache=MemcachedBytecodeCache(
                                cache, prefix="jinja::",
                                timeout=3600))


    ## Let's customize the template loader to first look into
    ## /opt/invenio/etc-local/templates and then into /opt/invenio/etc/templates
    _app.jinja_loader = FileSystemLoader([join(CFG_ETCDIR + '-local', 'templates'), join(CFG_ETCDIR, 'templates')])

    ## Let's attach our session handling (which is bridging with the native Invenio session handling
    _app.session_interface = InvenioSessionInterface()

    ## Let's load the whole invenio.config into Flask :-) ...
    _app.config.from_object(config)

    ## ... and map certain common parameters
    _app.config["SECRET_KEY"] = 'Inv3n10'
    _app.config['SESSION_COOKIE_NAME'] = CFG_WEBSESSION_COOKIE_NAME
    _app.config['PERMANENT_SESSION_LIFETIME'] = CFG_WEBSESSION_EXPIRY_LIMIT_REMEMBER * CFG_WEBSESSION_ONE_DAY
    _app.config['USE_X_SENDFILE'] = CFG_BIBDOCFILE_USE_XSENDFILE
    _app.config['DEBUG'] = False #CFG_DEVEL_SITE
    _app.debug = False #True #CFG_DEVEL_SITE
    _app.config['CFG_LANGUAGE_LIST_LONG'] = [(lang, longname.decode('utf-8')) for (lang, longname) in language_list_long()]

    ## Invenio is all using str objects. Let's change them to unicode
    _app.config.update(unicodifier(dict(_app.config)))

    ## Cache
    _app.config['CACHE_TYPE'] = CFG_FLASK_CACHE_TYPE
    cache.init_app(_app)

    _flask_log_handler = RotatingFileHandler(os.path.join(CFG_LOGDIR, 'flask.log'))
    _flask_log_handler.setFormatter(Formatter(
        '%(asctime)s %(levelname)s: %(message)s '
        '[in %(pathname)s:%(lineno)d]'
    ))
    _app.logger.addHandler(_flask_log_handler)

    # Let's create login manager.
    _login_manager = InvenioLoginManager()
    _login_manager.login_view = 'youraccount.login'
    _login_manager.setup_app(_app)

    # Let's create main menu.
    class Menu(object):
        def __init__(self, id='', title='', url='', order=None, children=None,
                     display=lambda:True):
            self.id = id
            self.title = title
            self.url = url
            self.children = children or {}
            self.order = order or 100
            self.display = display

    # Let's create assets environment.
    _assets = Environment(_app)
    _assets.debug = True #config.CFG_DEVEL_SITE == 1
    _assets.directory = config.CFG_WEBDIR

    _app.jinja_env.extend(new_bundle=lambda tag, collection: \
        Bundle(output="%s/invenio-%s.%s" % \
               (tag, hash('|'.join(collection)), tag),
               *collection))
    _app.jinja_env.add_extension(CollectionExtension)
    _app.jinja_env.add_extension('jinja2.ext.do')

    # Let's create Gravatar bridge.
    _gravatar = Gravatar(_app,
                    size=100,
                    rating='g',
                    default='retro',
                    force_default=False,
                    force_lower=False)

    @_login_manager.user_loader
    def _load_user(uid):
        """
        Function should not raise an exception if uid is not valid
        or User was not found in database.
        """
        try:
            from invenio.webuser_flask import UserInfo, current_user
            try:
                _app.logger.info("==== %s ====" % str(type(current_user._get_current_object())))
                #return current_user._get_current_object()
            except:
                _app.logger.info("==== CREATING NEW UserInfo OBJECT ====")
            return UserInfo()
        except:
            return None

    @_app.before_request
    def _populate_user_info():
        """
        Before every request being handled, let's compute the user_info dictionary
        which is used everywhere in Invenio to describe a user.

        This user_info dictionary is also stored in the session (under the 'user_info'
        key) and in the Flask global variable (under the 'user_info' attribute).
        """
        #from invenio.webuser_flask import UserInfo
        #g.user_info = UserInfo(session)
        pass

    @_app.before_request
    def _guess_language():
        """
        Before every request being handled, let's compute the language needed to
        return the answer to the client.

        This information will then be available in the session['ln'] and in g.ln.

        Additionally under g._ an already configured internationalization function
        will be available (configured to return unicode objects).
        """
        required_ln = None
        try:
            values = request.values
        except:
            values = {}
        if "ln" in values:
            ## If ln is specified explictly as a GET or POST argument
            ## let's take it!
            passed_ln = str(values["ln"])
            required_ln = wash_language(passed_ln)
            if passed_ln != required_ln:
                ## But only if it was a valid language
                required_ln = None
        if required_ln:
            ## Ok it was. We store it in the session.
            session["ln"] = required_ln
        if not "ln" in session:
            ## If there is no language saved into the session...
            if "user_info" in session and session["user_info"].get("language"):
                ## ... and the user is logged in, we try to take it from its
                ## settings.
                session["ln"] = session["user_info"]["language"]
            else:
                ## Otherwise we try to guess it from its request headers
                for value, quality in request.accept_languages:
                    value = str(value)
                    ln = wash_language(value)
                    if ln == value or ln[:2] == value[:2]:
                        session["ln"] = ln
                        break
                else:
                    ## Too bad! We stick to the default :-)
                    session["ln"] = CFG_SITE_LANG
        ## Well, let's make it global now
        g.ln = session["ln"]
        g._ = gettext_set_language(g.ln, use_unicode=True)

    @_app.template_filter('quoted_txt2html')
    def _quoted_txt2html(*args, **kwargs):
        return email_quoted_txt2html(*args, **kwargs)

    @_app.template_filter('invenio_format_date')
    def _format_date(date):
        """
        This is a special Jinja2 filter that will call convert_datetext_to_dategui
        to print a human friendly date.
        """
        if isinstance(date, datetime):
            return convert_datestruct_to_dategui(date.timetuple(), g.ln).decode('utf-8')
        return convert_datetext_to_dategui(date, g.ln).decode('utf-8')

    @_app.template_filter('invenio_url_args')
    def _url_args(d, append=u'?', filter=[]):
        from jinja2.utils import escape
        rv = append + u'&'.join(
            u'%s=%s' % (escape(key), escape(value))
            for key, value in d.iteritems(True)
            if value is not None and key not in filter
            # and not isinstance(value, Undefined)
        )
        return rv

    @_app.context_processor
    def _inject_utils():
        """
        This will add some more variables and functions to the Jinja2 to execution
        context. In particular it will add:

        - `url_for`: an Invenio specific wrapper of Flask url_for, that will let you
                     obtain URLs for non Flask-native handlers (i.e. not yet ported
                     Invenio URLs)
        - `breadcrumbs`: this will be a list of three-elements tuples, containing
{'fraction_non_alphanumeric': 0.08416130917592052, 'fraction_numerical': 0.0052183351423561826, 'mean_word_length': 2.527982326951399, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6809776', 'n_tokens_mistral': 7077, 'n_tokens_neox': 6750, 'n_words': 1942}