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

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

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

File size: 5.9 KB
Line 
1import os, sys
2
3import cherrypy
4from mako.template import Template
5from mako.lookup import TemplateLookup
6import simplejson
7import datetime, decimal
8from StringIO import StringIO
9from invirt.config import structs as config
10from webcommon import State
11
12
13class MakoHandler(cherrypy.dispatch.LateParamPageHandler):
14    """Callable which processes a dictionary, returning the rendered body."""
15   
16    def __init__(self, template, next_handler,
17                 content_type='text/html; charset=utf-8'):
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 = {}
33
34    def get_lookup(self, directories, module_directory=None,
35                     collection_size=-1, imports=[], **kwargs):
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',
47                                    imports=imports,
48                                    )
49            self.lookups[key] = lookup
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=[]):
55        cherrypy.request.lookup = lookup = self.get_lookup(
56            directories, module_directory, collection_size, imports)
57        cherrypy.request.template = t = lookup.get_template(filename)
58        cherrypy.request.handler = MakoHandler(
59            t, cherrypy.request.handler, content_type)
60
61cherrypy.tools.mako = cherrypy.Tool('on_start_resource', MakoLoader())
62
63
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
73
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
89
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
99
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
106cherrypy.tools.jsonify = cherrypy.Tool('before_finalize',
107                                       jsonify_tool_callback, priority=30)
108
109
110def require_login():
111    """If the user isn't logged in, raise 403 with an error."""
112    if cherrypy.request.login is False:
113        raise cherrypy.HTTPError(403,
114            "You are not authorized to access that resource")
115
116cherrypy.tools.require_login = cherrypy.Tool('on_start_resource',
117                                             require_login, priority=150)
118
119
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
126cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource',
127                                            require_POST, priority=150)
128
129
130def remote_user_login():
131    """Get remote user from SSL or GSSAPI, and store in request object.
132
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"""
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):
147            cherrypy.request.login = False # failed to log in
148        else:
149            cherrypy.request.login = user.split('@')[0].replace('/', '.')
150    else:
151        cherrypy.request.login = user
152
153cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource',
154                                                 remote_user_login, priority=50)
155
156
157def invirtwebstate_init():
158    """Initialize the cherrypy.request.state object from Invirt"""
159    if not hasattr(cherrypy.request, "state"):
160        cherrypy.request.state = State(cherrypy.request.login)
161
162cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource',
163                                              invirtwebstate_init, priority=100)
164
165
166class View(object):
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.