source: package_branches/invirt-web/cherrypy/code/view.py @ 2640

Last change on this file since 2640 was 2532, checked in by quentin, 14 years ago

Clarify the operation of MakoHandler?

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