source: trunk/packages/invirt-web/code/view.py @ 2737

Last change on this file since 2737 was 2737, checked in by broder, 14 years ago

Merge cherrypy-rebased branch of invirt-web into trunk.

File size: 5.9 KB
RevLine 
[2693]1import os, sys
[2659]2
3import cherrypy
4from mako.template import Template
5from mako.lookup import TemplateLookup
6import simplejson
7import datetime, decimal
[2693]8from StringIO import StringIO
[2669]9from invirt.config import structs as config
10from webcommon import State
[2659]11
[2723]12
[2659]13class MakoHandler(cherrypy.dispatch.LateParamPageHandler):
[2721]14    """Callable which processes a dictionary, returning the rendered body."""
[2659]15   
[2724]16    def __init__(self, template, next_handler,
17                 content_type='text/html; charset=utf-8'):
[2659]18        self.template = template
19        self.next_handler = next_handler
20        self.content_type = content_type
21   
22    def __call__(self):
23        env = globals().copy()
24        env.update(self.next_handler())
25        cherrypy.response.headers['Content-Type'] = self.content_type
26        return self.template.render(**env)
27       
28
29class MakoLoader(object):
30   
31    def __init__(self):
32        self.lookups = {}
[2693]33
34    def get_lookup(self, directories, module_directory=None,
35                     collection_size=-1, imports=[], **kwargs):
[2659]36        # Find the appropriate template lookup.
37        key = (tuple(directories), module_directory)
38        try:
39            lookup = self.lookups[key]
40        except KeyError:
41            lookup = TemplateLookup(directories=directories,
42                                    module_directory=module_directory,
43                                    collection_size=collection_size,
44                                    default_filters=['decode.utf8'],
45                                    input_encoding='utf-8',
46                                    output_encoding='utf-8',
[2673]47                                    imports=imports,
[2659]48                                    )
49            self.lookups[key] = lookup
[2693]50        return lookup
51
52    def __call__(self, filename, directories, module_directory=None,
53                 collection_size=-1, content_type='text/html; charset=utf-8',
54                 imports=[]):
[2724]55        cherrypy.request.lookup = lookup = self.get_lookup(
56            directories, module_directory, collection_size, imports)
[2659]57        cherrypy.request.template = t = lookup.get_template(filename)
[2724]58        cherrypy.request.handler = MakoHandler(
59            t, cherrypy.request.handler, content_type)
[2659]60
[2699]61cherrypy.tools.mako = cherrypy.Tool('on_start_resource', MakoLoader())
[2659]62
[2723]63
[2693]64def revertStandardError():
65    """Move stderr to stdout, and return the contents of the old stderr."""
66    errio = sys.stderr
67    if not isinstance(errio, StringIO):
68        return ''
69    sys.stderr = sys.stdout
70    errio.seek(0)
71    return errio.read()
72
[2723]73
[2693]74def catchStderr():
75    old_handler = cherrypy.request.handler
76    def wrapper(*args, **kwargs):
77        sys.stderr = StringIO()
78        ret = old_handler(*args, **kwargs)
79        e = revertStandardError()
80        if e:
81            if isinstance(ret, dict):
82                ret["error_text"] = e
83        return ret
84    if old_handler:
85        cherrypy.request.handler = wrapper
86
87cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr)
88
[2723]89
[2659]90class JSONEncoder(simplejson.JSONEncoder):
91        def default(self, obj):
92                if isinstance(obj, datetime.datetime):
93                        return str(obj)
94                elif isinstance(obj, decimal.Decimal):
95                        return float(obj)
96                else:
97                        return simplejson.JSONEncoder.default(self, obj)
98
[2723]99
[2659]100def jsonify_tool_callback(*args, **kwargs):
101    if not cherrypy.request.cached:
102        response = cherrypy.response
103        response.headers['Content-Type'] = 'text/javascript'
104        response.body = JSONEncoder().iterencode(response.body)
105
[2724]106cherrypy.tools.jsonify = cherrypy.Tool('before_finalize',
107                                       jsonify_tool_callback, priority=30)
[2659]108
[2723]109
[2665]110def require_login():
111    """If the user isn't logged in, raise 403 with an error."""
[2712]112    if cherrypy.request.login is False:
[2665]113        raise cherrypy.HTTPError(403,
114            "You are not authorized to access that resource")
115
[2724]116cherrypy.tools.require_login = cherrypy.Tool('on_start_resource',
117                                             require_login, priority=150)
[2665]118
[2723]119
[2685]120def require_POST():
121    """If the request isn't a POST request, raise 405 Method Not Allowed"""
122    if cherrypy.request.method != "POST":
123        raise cherrypy.HTTPError(405,
124                                 "You must submit this request with POST")
125
[2724]126cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource',
127                                            require_POST, priority=150)
[2685]128
[2723]129
[2670]130def remote_user_login():
[2722]131    """Get remote user from SSL or GSSAPI, and store in request object.
[2712]132
[2722]133Get the current user based on environment variables set by SSL or
134GSSAPI, and store it in the attribute cherrpy.request.login.
135
136Per the CherryPy API (http://www.cherrypy.org/wiki/RequestObject#login),
137the attribute is set to the username on successful login, to False on
138failed login, and is left at None if the user attempted no authentication.
139"""
[2670]140    environ = cherrypy.request.wsgi_environ
141    user = environ.get('REMOTE_USER')
142    if user is None:
143        return
144    if environ.get('AUTH_TYPE') == 'Negotiate':
145        # Convert the krb5 principal into a krb4 username
146        if not user.endswith('@%s' % config.kerberos.realm):
[2722]147            cherrypy.request.login = False # failed to log in
[2670]148        else:
149            cherrypy.request.login = user.split('@')[0].replace('/', '.')
150    else:
151        cherrypy.request.login = user
152
[2724]153cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource',
154                                                 remote_user_login, priority=50)
[2670]155
[2723]156
[2669]157def invirtwebstate_init():
158    """Initialize the cherrypy.request.state object from Invirt"""
[2690]159    if not hasattr(cherrypy.request, "state"):
160        cherrypy.request.state = State(cherrypy.request.login)
[2669]161
[2724]162cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource',
163                                              invirtwebstate_init, priority=100)
[2669]164
[2723]165
[2659]166class View(object):
[2724]167    _cp_config = {'tools.mako.directories':
168                      [os.path.join(os.path.dirname(__file__),'templates')]}
Note: See TracBrowser for help on using the repository browser.