<commit_before>#--
# Copyright (c) 2008, 2009, 2010 Net-ng.
# All rights reserved.
#
# This software is licensed under the BSD License, as described in
# the file LICENSE.txt, which you should have received as part of
# this distribution.
#--

"""A ``WSGIApp`` object is an intermediary object between a publisher and the
root component of the application

A ``WSGIApp`` conforms to the WSGI interface and has a component factory. So,
each time the ``WSGIApp`` receives a request without a session id or with an
expired session id, it creates a new root component and a new session.
"""
from __future__ import with_statement

import sys

import webob
from webob import exc, acceptparse

from nagare import component, presentation, serializer, database, top, security, log, comet
from nagare.security import dummy_manager
from nagare.callbacks import Callbacks, CallbackLookupError
from nagare.namespaces import xhtml

from nagare.sessions import ExpirationError

# ---------------------------------------------------------------------------

class MIMEAcceptWithoutWildcards(acceptparse.Accept):
    def _match(self, item, match):
        if '*' in item:
            return False
        return super(MIMEAcceptWithoutWildcards, self)._match(item, match)


class Response(webob.Response):
    def __init__(self, accept):
        super(Response, self).__init__(headerlist=[])

        accept = MIMEAcceptWithoutWildcards('Accept', accept)
        self.xml_output = accept.best_match(('text/html', 'application/xhtml+xml')) == 'application/xhtml+xml'

        self.content_type = ''
        self.doctype = None

# ---------------------------------------------------------------------------

class WSGIApp(object):
    def __init__(self, root_factory):
        """Initialization

        In:
          - ``root_factory`` -- function to create the application root component
          - ``databases`` -- the SQLAlchemy metadata objects and the database engines settings
        """
        self.root_factory = root_factory

        self.static_path = ''
        self.static_url = ''
        self.databases = []
        self.name = ''
        self.project_name = ''
        self.redirect_after_post = False
        self.always_html = True
        self.sessions = None
        self.last_exception = None

        self.security = dummy_manager.Manager()

    def set_config(self, config_filename, config, error):
        """Read the configuration parameters

        In:
          - ``config_filename`` -- the path to the configuration file
          - ``config`` -- the ``ConfigObj`` object, created from the configuration file
          - ``error`` -- the function to call in case of configuration errors
        """
        self.name = config['application']['name']
        self.redirect_after_post = config['application']['redirect_after_post']
        self.always_html = config['application']['always_html']

    def set_static_path(self, static_path):
        """Register the directory of the static contents

        In:
          - ``static_path`` -- the directory where the static contents of the application
            are located
        """
        self.static_path = static_path

    def set_static_url(self, static_url):
        """Register the url of the static contents

        In:
          - ``static_url`` -- the url of the static contents of the application
        """
        self.static_url = static_url

    def set_publisher(self, publisher):
        """Register the publisher

        In:
          - ``publisher`` -- the publisher of the application
        """
        pass

    def set_sessions_manager(self, sessions_manager):
        """Register the sessions manager

        In:
          - ``sessions_manager`` -- the sessions manager
        """
        self.sessions = sessions_manager

    def set_databases(self, databases):
        """Register the databases properties

        In:
          - ``databases`` -- the SQLAlchemy metadata objects and the database engines settings
        """
        self.databases = databases

    def start(self):
        """Call after each process start
        """
        for database_settings in self.databases:
            database.set_metadata(*database_settings)

    def set_project(self, name):
        """The application distribution name

        In:
          - ``project_name`` -- name of the distutils distribution where the app is located
        """
        self.project_name = name

    # -----------------------------------------------------------------------

    def on_bad_http_method(self, request, response):
        """A HTTP request other than a GET or PUT was received

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - raise a ``webob.exc`` object, used to generate the response to the browser
        """
        raise exc.HTTPMethodNotAllowed()

    def on_incomplete_url(self, request, response):
        """An URL without an application name was received

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - raise a ``webob.exc`` object, used to generate the response to the browser
        """
        raise exc.HTTPMovedPermanently(add_slash=True)

    def on_session_expired(self, request, response):
        """The session id received is invalid

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - raise a ``webob.exc`` object, used to generate the response to the browser
        """
        raise exc.HTTPMovedPermanently()

    def on_back(self, request, response, h, output):
        """The user used the back button

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``h`` -- the current renderer
          - ``output`` -- the tree for the refreshed page

        Return:
          - a tree
        """
        return output

    def on_callback_lookuperror(self, request, response, async):
        """A callback was not found

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``async`` -- is an XHR request ?
        """
        if not async:
            raise

        # As the XHR requests use the same continuation, a callback
        # can be not found (i.e deleted by a previous XHR)
        # In this case, do nothing
        return lambda h: ''

    def on_after_post(self, request, response, ids):
        """Generate a redirection after a POST

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``ids`` -- identifiers to put into the generated redirection URL

        Return:
          - a ``webob.exc`` object, used to generate the response to the browser
        """
        return exc.HTTPSeeOther(location=request.path_url + '?' + '&'.join(ids))

    def on_exception(self, request, response):
        """Method called when an exception occurs

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - a ``webob`` response object
        """
        raise

    # -----------------------------------------------------------------------

    def create_root(self, *args, **kw):
        """Create the application root component

        Return:
          - the root component
        """
        return self.root_factory(*args, **kw)

    def create_renderer(self, async, session, request, response, callbacks):
        """Create the initial renderer (the root of all the used renderers)

        In:
          - ``async`` -- is an XHR request ?
          - ``session`` -- the session
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``callbacks`` -- object to register the callbacks
        """
        renderer_factory = xhtml.AsyncRenderer if async else xhtml.Renderer
        return renderer_factory(
                                None,
                                session,
                                request, response,
                                callbacks,
                                self.static_url, self.static_path,
                                request.script_name
                               )

    def start_request(self, root, request, response):
        """A new request is received, setup its dedicated environment

        In:
          - ``root`` -- the application root component
          - ``request`` -- the web request object
          - ``response`` -- the web response object
        """
        security.set_manager(self.security) # Set the security manager<commit_msg>Easy way to change the default renderer in a `WSIApp` class, by changing its `renderer_factory` attribute<commit_after>#--
# Copyright (c) 2008, 2009, 2010 Net-ng.
# All rights reserved.
#
# This software is licensed under the BSD License, as described in
# the file LICENSE.txt, which you should have received as part of
# this distribution.
#--

"""A ``WSGIApp`` object is an intermediary object between a publisher and the
root component of the application

A ``WSGIApp`` conforms to the WSGI interface and has a component factory. So,
each time the ``WSGIApp`` receives a request without a session id or with an
expired session id, it creates a new root component and a new session.
"""
from __future__ import with_statement

import sys

import webob
from webob import exc, acceptparse

from nagare import component, presentation, serializer, database, top, security, log, comet
from nagare.security import dummy_manager
from nagare.callbacks import Callbacks, CallbackLookupError
from nagare.namespaces import xhtml

from nagare.sessions import ExpirationError

# ---------------------------------------------------------------------------

class MIMEAcceptWithoutWildcards(acceptparse.Accept):
    def _match(self, item, match):
        if '*' in item:
            return False
        return super(MIMEAcceptWithoutWildcards, self)._match(item, match)


class Response(webob.Response):
    def __init__(self, accept):
        super(Response, self).__init__(headerlist=[])

        accept = MIMEAcceptWithoutWildcards('Accept', accept)
        self.xml_output = accept.best_match(('text/html', 'application/xhtml+xml')) == 'application/xhtml+xml'

        self.content_type = ''
        self.doctype = None

# ---------------------------------------------------------------------------

class WSGIApp(object):
    renderer_factory = xhtml.Renderer   # Default renderer

    def __init__(self, root_factory):
        """Initialization

        In:
          - ``root_factory`` -- function to create the application root component
          - ``databases`` -- the SQLAlchemy metadata objects and the database engines settings
        """
        self.root_factory = root_factory

        self.static_path = ''
        self.static_url = ''
        self.databases = []
        self.name = ''
        self.project_name = ''
        self.redirect_after_post = False
        self.always_html = True
        self.sessions = None
        self.last_exception = None

        self.security = dummy_manager.Manager()

    def set_config(self, config_filename, config, error):
        """Read the configuration parameters

        In:
          - ``config_filename`` -- the path to the configuration file
          - ``config`` -- the ``ConfigObj`` object, created from the configuration file
          - ``error`` -- the function to call in case of configuration errors
        """
        self.name = config['application']['name']
        self.redirect_after_post = config['application']['redirect_after_post']
        self.always_html = config['application']['always_html']

    def set_static_path(self, static_path):
        """Register the directory of the static contents

        In:
          - ``static_path`` -- the directory where the static contents of the application
            are located
        """
        self.static_path = static_path

    def set_static_url(self, static_url):
        """Register the url of the static contents

        In:
          - ``static_url`` -- the url of the static contents of the application
        """
        self.static_url = static_url

    def set_publisher(self, publisher):
        """Register the publisher

        In:
          - ``publisher`` -- the publisher of the application
        """
        pass

    def set_sessions_manager(self, sessions_manager):
        """Register the sessions manager

        In:
          - ``sessions_manager`` -- the sessions manager
        """
        self.sessions = sessions_manager

    def set_databases(self, databases):
        """Register the databases properties

        In:
          - ``databases`` -- the SQLAlchemy metadata objects and the database engines settings
        """
        self.databases = databases

    def start(self):
        """Call after each process start
        """
        for database_settings in self.databases:
            database.set_metadata(*database_settings)

    def set_project(self, name):
        """The application distribution name

        In:
          - ``project_name`` -- name of the distutils distribution where the app is located
        """
        self.project_name = name

    # -----------------------------------------------------------------------

    def on_bad_http_method(self, request, response):
        """A HTTP request other than a GET or PUT was received

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - raise a ``webob.exc`` object, used to generate the response to the browser
        """
        raise exc.HTTPMethodNotAllowed()

    def on_incomplete_url(self, request, response):
        """An URL without an application name was received

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - raise a ``webob.exc`` object, used to generate the response to the browser
        """
        raise exc.HTTPMovedPermanently(add_slash=True)

    def on_session_expired(self, request, response):
        """The session id received is invalid

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - raise a ``webob.exc`` object, used to generate the response to the browser
        """
        raise exc.HTTPMovedPermanently()

    def on_back(self, request, response, h, output):
        """The user used the back button

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``h`` -- the current renderer
          - ``output`` -- the tree for the refreshed page

        Return:
          - a tree
        """
        return output

    def on_callback_lookuperror(self, request, response, async):
        """A callback was not found

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``async`` -- is an XHR request ?
        """
        if not async:
            raise

        # As the XHR requests use the same continuation, a callback
        # can be not found (i.e deleted by a previous XHR)
        # In this case, do nothing
        return lambda h: ''

    def on_after_post(self, request, response, ids):
        """Generate a redirection after a POST

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``ids`` -- identifiers to put into the generated redirection URL

        Return:
          - a ``webob.exc`` object, used to generate the response to the browser
        """
        return exc.HTTPSeeOther(location=request.path_url + '?' + '&'.join(ids))

    def on_exception(self, request, response):
        """Method called when an exception occurs

        In:
          - ``request`` -- the web request object
          - ``response`` -- the web response object

        Return:
          - a ``webob`` response object
        """
        raise

    # -----------------------------------------------------------------------

    def create_root(self, *args, **kw):
        """Create the application root component

        Return:
          - the root component
        """
        return self.root_factory(*args, **kw)

    def create_renderer(self, async, session, request, response, callbacks):
        """Create the initial renderer (the root of all the used renderers)

        In:
          - ``async`` -- is an XHR request ?
          - ``session`` -- the session
          - ``request`` -- the web request object
          - ``response`` -- the web response object
          - ``callbacks`` -- object to register the callbacks
        """
        renderer = self.renderer_factory(
                                            None,
                                            session,
                                            request, response,
                                            callbacks,
                                            self.static_url, self.static_path,
                                            request.script_name
                                        )

        if async:
            renderer = renderer.AsyncRenderer(
                                                None,
                                                session,
                                                request, response,
                                                callbacks,
                                                self.static_url, self.static_path,
                                                request.script_name
                                             )

        return renderer

    def start_request(self, root, request, response):
        """A new request is received, setup its dedicated environment

        In:
          - ``root`` -- the application root component
          - ``request`` -- the web request object
          - ``response`` -- the web response object
        """
        security.set_manager(self.security) # Set the security manager
{'fraction_non_alphanumeric': 0.12199610305260879, 'fraction_numerical': 0.0012989824637367395, 'mean_word_length': 1.7573496493060736, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 27, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1722950', 'n_tokens_mistral': 4463, 'n_tokens_neox': 4314, 'n_words': 1570}