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

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

view.py: double blank lines at toplevel

This is a style convention that makes it easier to see where one
definition ends and the next begins. It's particularly necessary
in this file, because it can separate the CherryPy? glue associated
with one function from the unrelated function below it.

File size: 5.6 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, 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
61
62def revertStandardError():
63    """Move stderr to stdout, and return the contents of the old stderr."""
64    errio = sys.stderr
65    if not isinstance(errio, StringIO):
66        return ''
67    sys.stderr = sys.stdout
68    errio.seek(0)
69    return errio.read()
70
71
72def catchStderr():
73    old_handler = cherrypy.request.handler
74    def wrapper(*args, **kwargs):
75        sys.stderr = StringIO()
76        ret = old_handler(*args, **kwargs)
77        e = revertStandardError()
78        if e:
79            if isinstance(ret, dict):
80                ret["error_text"] = e
81        return ret
82    if old_handler:
83        cherrypy.request.handler = wrapper
84
85cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr)
86
87
88class JSONEncoder(simplejson.JSONEncoder):
89        def default(self, obj):
90                if isinstance(obj, datetime.datetime):
91                        return str(obj)
92                elif isinstance(obj, decimal.Decimal):
93                        return float(obj)
94                else:
95                        return simplejson.JSONEncoder.default(self, obj)
96
97
98def jsonify_tool_callback(*args, **kwargs):
99    if not cherrypy.request.cached:
100        response = cherrypy.response
101        response.headers['Content-Type'] = 'text/javascript'
102        response.body = JSONEncoder().iterencode(response.body)
103
104cherrypy.tools.jsonify = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30)
105
106
107def require_login():
108    """If the user isn't logged in, raise 403 with an error."""
109    if cherrypy.request.login is False:
110        raise cherrypy.HTTPError(403,
111            "You are not authorized to access that resource")
112
113cherrypy.tools.require_login = cherrypy.Tool('on_start_resource', require_login, priority=150)
114
115
116def require_POST():
117    """If the request isn't a POST request, raise 405 Method Not Allowed"""
118    if cherrypy.request.method != "POST":
119        raise cherrypy.HTTPError(405,
120                                 "You must submit this request with POST")
121
122cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource', require_POST, priority=150)
123
124
125def remote_user_login():
126    """Get remote user from SSL or GSSAPI, and store in request object.
127
128Get the current user based on environment variables set by SSL or
129GSSAPI, and store it in the attribute cherrpy.request.login.
130
131Per the CherryPy API (http://www.cherrypy.org/wiki/RequestObject#login),
132the attribute is set to the username on successful login, to False on
133failed login, and is left at None if the user attempted no authentication.
134"""
135    environ = cherrypy.request.wsgi_environ
136    user = environ.get('REMOTE_USER')
137    if user is None:
138        return
139    if environ.get('AUTH_TYPE') == 'Negotiate':
140        # Convert the krb5 principal into a krb4 username
141        if not user.endswith('@%s' % config.kerberos.realm):
142            cherrypy.request.login = False # failed to log in
143        else:
144            cherrypy.request.login = user.split('@')[0].replace('/', '.')
145    else:
146        cherrypy.request.login = user
147
148cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource', remote_user_login, priority=50)
149
150
151def invirtwebstate_init():
152    """Initialize the cherrypy.request.state object from Invirt"""
153    if not hasattr(cherrypy.request, "state"):
154        cherrypy.request.state = State(cherrypy.request.login)
155
156cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource', invirtwebstate_init, priority=100)
157
158
159class View(object):
160    _cp_config = {'tools.mako.directories': [os.path.join(os.path.dirname(__file__),'templates')]}
Note: See TracBrowser for help on using the repository browser.