42
43
from ivle import util
44
46
from ivle.dispatch.request import Request
45
import ivle.webapp.security
46
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
47
from ivle.dispatch import login
48
from ivle.webapp.base.plugins import ViewPlugin
47
49
from ivle.webapp.errors import HTTPError, Unauthorized
49
def generate_route_mapper(view_plugins, attr):
53
# XXX List of plugins, which will eventually be read in from conf
55
'ivle.webapp.core#Plugin',
56
'ivle.webapp.admin.user#Plugin',
57
'ivle.webapp.tutorial#Plugin',
58
'ivle.webapp.admin.subject#Plugin',
59
'ivle.webapp.filesystem.browser#Plugin',
60
'ivle.webapp.filesystem.diff#Plugin',
61
'ivle.webapp.filesystem.svnlog#Plugin',
62
'ivle.webapp.groups#Plugin',
63
'ivle.webapp.console#Plugin',
64
'ivle.webapp.security#Plugin',
65
'ivle.webapp.media#Plugin',
66
'ivle.webapp.forum#Plugin',
67
'ivle.webapp.help#Plugin',
68
'ivle.webapp.tos#Plugin',
71
def generate_route_mapper(view_plugins):
51
73
Build a Mapper object for doing URL matching using 'routes', based on the
52
74
given plugin registry.
100
129
# Hack? Try and get the user login early just in case we throw an error
101
130
# (most likely 404) to stop us seeing not logged in even when we are.
102
131
if not req.publicmode:
103
user = ivle.webapp.security.get_user_details(req)
132
user = login.get_user_details(req)
105
134
# Don't set the user if it is disabled or hasn't accepted the ToS.
106
135
if user and user.valid:
109
conf = ivle.config.Config()
113
req.mapper = generate_route_mapper(conf.plugin_index[PublicViewPlugin],
116
req.mapper = generate_route_mapper(conf.plugin_index[ViewPlugin],
138
### BEGIN New plugins framework ###
139
# XXX This should be done ONCE per Python process, not per request.
141
# XXX No authentication is done here
142
req.plugins = dict([get_plugin(pluginstr) for pluginstr in plugins_HACK])
143
# Index the plugins by base class
144
req.plugin_index = {}
145
for plugin in req.plugins.values():
146
# Getmro returns a tuple of all the super-classes of the plugin
147
for base in inspect.getmro(plugin):
148
if base not in req.plugin_index:
149
req.plugin_index[base] = []
150
req.plugin_index[base].append(plugin)
151
req.reverse_plugins = dict([(v, k) for (k, v) in req.plugins.items()])
152
req.mapper = generate_route_mapper(req.plugin_index[ViewPlugin])
119
154
matchdict = req.mapper.match(req.uri)
120
155
if matchdict is not None:
160
193
req.store.commit()
163
return req.HTTP_NOT_FOUND # TODO: Prettify.
195
### END New plugins framework ###
197
# Check req.app to see if it is valid. 404 if not.
198
if req.app is not None and req.app not in ivle.conf.apps.app_url:
199
req.throw_error(Request.HTTP_NOT_FOUND,
200
"There is no application called %s." % repr(req.app))
202
# Special handling for public mode - only allow the public app, call it
204
# NOTE: This will not behave correctly if the public app uses
205
# write_html_head_foot, but "serve" does not.
207
if req.app != ivle.conf.apps.public_app:
208
req.throw_error(Request.HTTP_FORBIDDEN,
209
"This application is not available on the public site.")
210
app = ivle.conf.apps.app_url[ivle.conf.apps.public_app]
211
apps.call_app(app.dir, req)
214
# app is the App object for the chosen app
216
app = ivle.conf.apps.app_url[ivle.conf.apps.default_app]
218
app = ivle.conf.apps.app_url[req.app]
220
# Check if app requires auth. If so, perform authentication and login.
221
# This will either return a User object, None, or perform a redirect
222
# which we will not catch here.
224
logged_in = req.user is not None
228
assert logged_in # XXX
231
# Keep the user's session alive by writing to the session object.
232
# req.get_session().save()
233
# Well, it's a fine idea, but it creates considerable grief in the
234
# concurrent update department, so instead, we'll just make the
235
# sessions not time out.
236
req.get_session().unlock()
238
# If user did not specify an app, HTTP redirect to default app and
241
req.throw_redirect(util.make_path(ivle.conf.apps.default_app))
243
# Set the default title to the app's tab name, if any. Otherwise URL
245
if app.name is not None:
250
# Call the specified app with the request object
251
apps.call_app(app.dir, req)
253
# if not logged in, login.login will have written the login box.
254
# Just clean up and exit.
256
# MAKE SURE we write the HTTP (and possibly HTML) header. This
257
# wouldn't happen if nothing else ever got written, so we have to make
259
req.ensure_headers_written()
261
# When done, write out the HTML footer if the app has requested it
262
if req.write_html_head_foot:
263
html.write_html_foot(req)
265
# Note: Apache will not write custom HTML error messages here.
266
# Use req.throw_error to do that.
165
269
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):
220
325
logging.debug('Logging Unhandled Exception')
222
# A "bad" error message. We shouldn't get here unless IVLE
223
# misbehaves (which is currently very easy, if things aren't set up
225
# Write the traceback.
226
# If this is a non-4xx IVLEError, get the message and httpcode and
227
# make the error message a bit nicer (but still include the
229
# We also need to special-case IVLEJailError, as we can get another
230
# almost-exception out of it.
232
codename, msg = None, None
234
if exc_type is util.IVLEJailError:
235
msg = exc_value.type_str + ": " + exc_value.message
236
tb = 'Exception information extracted from IVLEJailError:\n'
237
tb += urllib.unquote(exc_value.info)
327
# We handle 3 types of error.
328
# IVLEErrors with 4xx response codes (client error).
329
# IVLEErrors with 5xx response codes (handled server error).
330
# Other exceptions (unhandled server error).
331
# IVLEErrors should not have other response codes than 4xx or 5xx
332
# (eg. throw_redirect should have been used for 3xx codes).
333
# Therefore, that is treated as an unhandled error.
335
if (exc_type == util.IVLEError and httpcode >= 400
336
and httpcode <= 499):
337
# IVLEErrors with 4xx response codes are client errors.
338
# Therefore, these have a "nice" response (we even coat it in the IVLE
341
req.write_html_head_foot = True
342
req.write_javascript_settings = False
343
req.write('<div id="ivle_padding">\n')
240
345
codename, msg = req.get_http_codename(httpcode)
241
346
except AttributeError:
347
codename, msg = None, None
243
348
# Override the default message with the supplied one,
245
if hasattr(exc_value, 'message') and exc_value.message is not None:
350
if exc_value.message is not None:
246
351
msg = exc_value.message
247
# Prepend the exception type
248
if exc_type != util.IVLEError:
249
msg = exc_type.__name__ + ": " + repr(msg)
251
tb = ''.join(traceback.format_exception(exc_type, exc_value,
255
logging.error('%s\n%s'%(str(msg), tb))
256
# Error messages are only displayed is the user is NOT a student,
257
# or if there has been a problem logging the error message
258
show_errors = (not publicmode) and ((login and \
259
str(role) != "student") or logfail)
260
req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
352
if codename is not None:
353
req.write("<h1>Error: %s</h1>\n" % cgi.escape(codename))
355
req.write("<h1>Error</h1>\n")
357
req.write("<p>%s</p>\n" % cgi.escape(msg))
359
req.write("<p>An unknown error occured.</p>\n")
362
logging.info(str(msg))
364
req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
366
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
367
%cgi.escape(logfile))
368
req.write('</div>\n')
369
html.write_html_foot(req)
371
# A "bad" error message. We shouldn't get here unless IVLE
372
# misbehaves (which is currently very easy, if things aren't set up
374
# Write the traceback.
375
# If this is a non-4xx IVLEError, get the message and httpcode and
376
# make the error message a bit nicer (but still include the
378
# We also need to special-case IVLEJailError, as we can get another
379
# almost-exception out of it.
381
codename, msg = None, None
383
if exc_type is util.IVLEJailError:
384
msg = exc_value.type_str + ": " + exc_value.message
385
tb = 'Exception information extracted from IVLEJailError:\n'
386
tb += urllib.unquote(exc_value.info)
389
codename, msg = req.get_http_codename(httpcode)
390
except AttributeError:
392
# Override the default message with the supplied one,
394
if hasattr(exc_value, 'message') and exc_value.message is not None:
395
msg = exc_value.message
396
# Prepend the exception type
397
if exc_type != util.IVLEError:
398
msg = exc_type.__name__ + ": " + msg
400
tb = ''.join(traceback.format_exception(exc_type, exc_value,
404
logging.error('%s\n%s'%(str(msg), tb))
405
# Error messages are only displayed is the user is NOT a student,
406
# or if there has been a problem logging the error message
407
show_errors = (not publicmode) and ((login and \
408
str(role) != "student") or logfail)
409
req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
261
410
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
262
411
<html xmlns="http://www.w3.org/1999/xhtml">
263
412
<head><title>IVLE Internal Server Error</title></head>
265
414
<h1>IVLE Internal Server Error""")
267
if (codename is not None
268
and httpcode != mod_python.apache.HTTP_INTERNAL_SERVER_ERROR):
269
req.write(": %s" % cgi.escape(codename))
416
if (codename is not None
417
and httpcode != mod_python.apache.HTTP_INTERNAL_SERVER_ERROR):
418
req.write(": %s" % cgi.escape(codename))
272
421
<p>An error has occured which is the fault of the IVLE developers or
273
422
administration. The developers have been notified.</p>
277
req.write("<p>%s</p>\n" % cgi.escape(msg))
278
if httpcode is not None:
279
req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
281
<p>Please report this to <a href="mailto:%s">%s</a> (the system
282
administrator). Include the following information:</p>
283
""" % (cgi.escape(admin_email), cgi.escape(admin_email)))
426
req.write("<p>%s</p>\n" % cgi.escape(msg))
427
if httpcode is not None:
428
req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
430
<p>Please report this to <a href="mailto:%s">%s</a> (the system
431
administrator). Include the following information:</p>
432
""" % (cgi.escape(admin_email), cgi.escape(admin_email)))
285
req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
287
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
288
%cgi.escape(logfile))
289
req.write("</body></html>")
434
req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
436
req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
437
%cgi.escape(logfile))
438
req.write("</body></html>")