4 from mako.template import Template
5 from mako.lookup import TemplateLookup
7 import datetime, decimal
8 from StringIO import StringIO
9 from invirt.config import structs as config
10 import invirt.database
11 from webcommon import State
14 class MakoHandler(cherrypy.dispatch.LateParamPageHandler):
15 """Callable which processes a dictionary, returning the rendered body."""
17 def __init__(self, template, next_handler,
18 content_type='text/html; charset=utf-8'):
19 self.template = template
20 self.next_handler = next_handler
21 self.content_type = content_type
24 env = globals().copy()
25 env.update(self.next_handler())
26 cherrypy.response.headers['Content-Type'] = self.content_type
27 return self.template.render(**env)
30 class MakoLoader(object):
35 def get_lookup(self, directories, module_directory=None,
36 collection_size=-1, imports=[], **kwargs):
37 # Find the appropriate template lookup.
38 key = (tuple(directories), module_directory)
40 lookup = self.lookups[key]
42 lookup = TemplateLookup(directories=directories,
43 module_directory=module_directory,
44 collection_size=collection_size,
45 default_filters=['decode.utf8'],
46 input_encoding='utf-8',
47 output_encoding='utf-8',
50 self.lookups[key] = lookup
53 def __call__(self, filename, directories, module_directory=None,
54 collection_size=-1, content_type='text/html; charset=utf-8',
56 cherrypy.request.lookup = lookup = self.get_lookup(
57 directories, module_directory, collection_size, imports)
58 cherrypy.request.template = t = lookup.get_template(filename)
59 cherrypy.request.handler = MakoHandler(
60 t, cherrypy.request.handler, content_type)
62 cherrypy.tools.mako = cherrypy.Tool('on_start_resource', MakoLoader())
65 def revertStandardError():
66 """Move stderr to stdout, and return the contents of the old stderr."""
68 if not isinstance(errio, StringIO):
70 sys.stderr = sys.stdout
76 old_handler = cherrypy.request.handler
77 def wrapper(*args, **kwargs):
78 sys.stderr = StringIO()
79 ret = old_handler(*args, **kwargs)
80 e = revertStandardError()
82 if isinstance(ret, dict):
86 cherrypy.request.handler = wrapper
88 cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr)
91 class JSONEncoder(simplejson.JSONEncoder):
92 def default(self, obj):
93 if isinstance(obj, datetime.datetime):
95 elif isinstance(obj, decimal.Decimal):
98 return simplejson.JSONEncoder.default(self, obj)
101 def jsonify_tool_callback(*args, **kwargs):
102 if not cherrypy.request.cached:
103 response = cherrypy.response
104 response.headers['Content-Type'] = 'text/javascript'
105 response.body = JSONEncoder().iterencode(response.body)
107 cherrypy.tools.jsonify = cherrypy.Tool('before_finalize',
108 jsonify_tool_callback, priority=30)
112 """If the user isn't logged in, raise 403 with an error."""
113 if cherrypy.request.login is False:
114 raise cherrypy.HTTPError(403,
115 "You are not authorized to access that resource")
117 cherrypy.tools.require_login = cherrypy.Tool('on_start_resource',
118 require_login, priority=150)
122 """If the request isn't a POST request, raise 405 Method Not Allowed"""
123 if cherrypy.request.method != "POST":
124 raise cherrypy.HTTPError(405,
125 "You must submit this request with POST")
126 if not cherrypy.request.headers.get('Referer', '').startswith('https://' + config.web.hostname):
127 raise cherrypy.HTTPError(403, "This form is only usable when submitted from another page on this site. If you receive this message in error, check your browser's Referer settings.")
129 cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource',
130 require_POST, priority=150)
133 def remote_user_login():
134 """Get remote user from SSL or GSSAPI, and store in request object.
136 Get the current user based on environment variables set by SSL or
137 GSSAPI, and store it in the attribute cherrpy.request.login.
139 Per the CherryPy API (http://www.cherrypy.org/wiki/RequestObject#login),
140 the attribute is set to the username on successful login, to False on
141 failed login, and is left at None if the user attempted no authentication.
143 environ = cherrypy.request.wsgi_environ
144 user = environ.get('REMOTE_USER')
147 if environ.get('AUTH_TYPE') == 'Negotiate':
148 # Convert the krb5 principal into a krb4 username
149 if not user.endswith('@%s' % config.kerberos.realm):
150 cherrypy.request.login = False # failed to log in
152 cherrypy.request.login = user.split('@')[0].replace('/', '.')
154 cherrypy.request.login = user
156 cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource',
157 remote_user_login, priority=50)
160 def invirtwebstate_init():
161 """Initialize the cherrypy.request.state object from Invirt"""
162 if not hasattr(cherrypy.request, "state"):
163 cherrypy.request.state = State(cherrypy.request.login)
165 cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource',
166 invirtwebstate_init, priority=100)
169 cherrypy.tools.clear_db_cache = cherrypy.Tool('on_start_resource', invirt.database.clear_cache)
173 _cp_config = {'tools.mako.directories':
174 [os.path.join(os.path.dirname(__file__),'templates')]}