~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/dispatch/__init__.py

  • Committer: William Grant
  • Date: 2009-01-13 01:36:15 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1123
Merge setup-refactor branch. This completely breaks existing installations;
every path (both filesystem and Python) has changed. Do not upgrade without
knowing what you are doing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# IVLE - Informatics Virtual Learning Environment
2
 
# Copyright (C) 2007-2009 The University of Melbourne
 
1
# IVLE
 
2
# Copyright (C) 2007-2008 The University of Melbourne
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
17
 
18
 
# Author: Matt Giuca, Will Grant
19
 
 
20
 
"""
21
 
This is a mod_python handler program. The correct way to call it is to have
22
 
Apache send all requests to be handled by the module 'dispatch'.
23
 
 
24
 
Top-level handler. Handles all requests to all pages in IVLE.
25
 
Handles authentication (not authorization).
26
 
Then passes the request along to the appropriate ivle app.
27
 
"""
 
18
# Module: dispatch
 
19
# Author: Matt Giuca
 
20
# Date: 11/12/2007
 
21
 
 
22
# This is a mod_python handler program. The correct way to call it is to have
 
23
# Apache send all requests to be handled by the module 'dispatch'.
 
24
 
 
25
# Top-level handler. Handles all requests to all pages in IVLE.
 
26
# Handles authentication (not authorization).
 
27
# Then passes the request along to the appropriate ivle app.
28
28
 
29
29
import sys
30
30
import os
35
35
import logging
36
36
import socket
37
37
import time
38
 
import inspect
39
38
 
40
39
import mod_python
41
 
import routes
 
40
from mod_python import apache, Cookie
42
41
 
43
42
from ivle import util
44
43
import ivle.conf
45
44
import ivle.conf.apps
46
 
from ivle.dispatch.request import Request
47
 
from ivle.dispatch import login
48
 
from ivle.webapp.base.plugins import ViewPlugin
49
 
from ivle.webapp.errors import HTTPError, Unauthorized
50
45
import apps
 
46
import login
51
47
import html
52
 
 
53
 
# XXX List of plugins, which will eventually be read in from conf
54
 
plugins_HACK = [
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',
69
 
70
 
 
71
 
def generate_route_mapper(view_plugins):
72
 
    """
73
 
    Build a Mapper object for doing URL matching using 'routes', based on the
74
 
    given plugin registry.
75
 
    """
76
 
    m = routes.Mapper(explicit=True)
77
 
    for plugin in view_plugins:
78
 
        # Establish a URL pattern for each element of plugin.urls
79
 
        assert hasattr(plugin, 'urls'), "%r does not have any urls" % plugin 
80
 
        for url in plugin.urls:
81
 
            routex = url[0]
82
 
            view_class = url[1]
83
 
            kwargs_dict = url[2] if len(url) >= 3 else {}
84
 
            m.connect(routex, view=view_class, **kwargs_dict)
85
 
    return m
86
 
 
87
 
def get_plugin(pluginstr):
88
 
    plugin_path, classname = pluginstr.split('#')
89
 
    # Load the plugin module from somewhere in the Python path
90
 
    # (Note that plugin_path is a fully-qualified Python module name).
91
 
    return (plugin_path,
92
 
            getattr(__import__(plugin_path, fromlist=[classname]), classname))
 
48
from request import Request
 
49
import plugins.console # XXX: Relies on www/ being in the Python path.
 
50
 
 
51
# List of cookies that IVLE uses (to be removed at logout)
 
52
ivle_cookies = ["ivleforumcookie", "clipboard"]
93
53
 
94
54
def handler(req):
95
55
    """Handles a request which may be to anywhere in the site except media.
106
66
        # yet.
107
67
        handle_unknown_exception(apachereq, *sys.exc_info())
108
68
        # Tell Apache not to generate its own errors as well
109
 
        return mod_python.apache.OK
 
69
        return apache.OK
110
70
 
111
71
    # Run the main handler, and catch all exceptions
112
72
    try:
118
78
    except Exception:
119
79
        handle_unknown_exception(req, *sys.exc_info())
120
80
        # Tell Apache not to generate its own errors as well
121
 
        return mod_python.apache.OK
 
81
        return apache.OK
122
82
 
123
83
def handler_(req, apachereq):
124
84
    """
131
91
    if not req.publicmode:
132
92
        req.user = login.get_user_details(req)
133
93
 
134
 
    ### BEGIN New plugins framework ###
135
 
    # XXX This should be done ONCE per Python process, not per request.
136
 
    # (Wait till WSGI)
137
 
    # XXX No authentication is done here
138
 
    req.plugins = dict([get_plugin(pluginstr) for pluginstr in plugins_HACK])
139
 
    # Index the plugins by base class
140
 
    req.plugin_index = {}
141
 
    for plugin in req.plugins.values():
142
 
        # Getmro returns a tuple of all the super-classes of the plugin
143
 
        for base in inspect.getmro(plugin):
144
 
            if base not in req.plugin_index:
145
 
                req.plugin_index[base] = []
146
 
            req.plugin_index[base].append(plugin)
147
 
    req.reverse_plugins = dict([(v, k) for (k, v) in req.plugins.items()])
148
 
    req.mapper = generate_route_mapper(req.plugin_index[ViewPlugin])
149
 
 
150
 
    matchdict = req.mapper.match(req.uri)
151
 
    if matchdict is not None:
152
 
        viewcls = matchdict['view']
153
 
        # Get the remaining arguments, less 'view', 'action' and 'controller'
154
 
        # (The latter two seem to be built-in, and we don't want them).
155
 
        kwargs = matchdict.copy()
156
 
        del kwargs['view']
157
 
        try:
158
 
            # Instantiate the view, which should be a BaseView class
159
 
            view = viewcls(req, **kwargs)
160
 
 
161
 
            # Check that the request (mainly the user) is permitted to access
162
 
            # the view.
163
 
            if not view.authorize(req):
164
 
                raise Unauthorized()
165
 
            # Render the output
166
 
            view.render(req)
167
 
        except HTTPError, e:
168
 
            # A view explicitly raised an HTTP error. Respect it.
169
 
            req.status = e.code
170
 
 
171
 
            # Try to find a custom error view.
172
 
            if hasattr(viewcls, 'get_error_view'):
173
 
                errviewcls = viewcls.get_error_view(e)
174
 
            else:
175
 
                errviewcls = None
176
 
 
177
 
            if errviewcls:
178
 
                errview = errviewcls(req, e)
179
 
                errview.render(req)
180
 
                return req.OK
181
 
            else:
182
 
                req.write(e.message)
183
 
                return e.code
184
 
        except Exception, e:
185
 
            # A non-HTTPError appeared. We have an unknown exception. Panic.
186
 
            handle_unknown_exception(req, *sys.exc_info())
187
 
            return req.OK
188
 
        else:
189
 
            req.store.commit()
190
 
            return req.OK
191
 
    ### END New plugins framework ###
192
 
 
193
94
    # Check req.app to see if it is valid. 404 if not.
194
95
    if req.app is not None and req.app not in ivle.conf.apps.app_url:
195
 
        req.throw_error(Request.HTTP_NOT_FOUND,
196
 
            "There is no application called %s." % repr(req.app))
 
96
        # Maybe it is a special app!
 
97
        if req.app == 'logout':
 
98
            logout(req)
 
99
        else:
 
100
            req.throw_error(Request.HTTP_NOT_FOUND,
 
101
                "There is no application called %s." % repr(req.app))
197
102
 
198
103
    # Special handling for public mode - only allow the public app, call it
199
104
    # and get out.
256
161
 
257
162
    # When done, write out the HTML footer if the app has requested it
258
163
    if req.write_html_head_foot:
 
164
        # Show the console if required
 
165
        if logged_in and app.useconsole:
 
166
            plugins.console.present(req, windowpane=True)
259
167
        html.write_html_foot(req)
260
168
 
261
169
    # Note: Apache will not write custom HTML error messages here.
262
170
    # Use req.throw_error to do that.
263
171
    return req.OK
264
172
 
 
173
def logout(req):
 
174
    """Log out the current user (if any) by destroying the session state.
 
175
    Then redirect to the top-level IVLE page."""
 
176
    session = req.get_session()
 
177
    session.invalidate()
 
178
    session.delete()
 
179
    # Invalidates all IVLE cookies
 
180
    all_cookies = Cookie.get_cookies(req)
 
181
    for cookie in all_cookies:
 
182
        if cookie in ivle_cookies:
 
183
            req.add_cookie(Cookie.Cookie(cookie,'',expires=1,path='/'))
 
184
    req.throw_redirect(util.make_path('')) 
 
185
 
265
186
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):
266
187
    """
267
188
    Given an exception that has just been thrown from IVLE, print its details
279
200
    # For some reason, some versions of mod_python have "_server" instead of
280
201
    # "main_server". So we check for both.
281
202
    try:
282
 
        admin_email = mod_python.apache.main_server.server_admin
 
203
        admin_email = apache.main_server.server_admin
283
204
    except AttributeError:
284
205
        try:
285
 
            admin_email = mod_python.apache._server.server_admin
 
206
            admin_email = apache._server.server_admin
286
207
        except AttributeError:
287
208
            admin_email = ""
288
209
    try:
290
211
        req.status = httpcode
291
212
    except AttributeError:
292
213
        httpcode = None
293
 
        req.status = mod_python.apache.HTTP_INTERNAL_SERVER_ERROR
294
 
    try:
295
 
        publicmode = req.publicmode
296
 
    except AttributeError:
297
 
        publicmode = True
 
214
        req.status = apache.HTTP_INTERNAL_SERVER_ERROR
298
215
    try:
299
216
        login = req.user.login
300
217
    except AttributeError:
301
218
        login = None
302
 
    try:
303
 
        role = req.user.role
304
 
    except AttributeError:
305
 
        role = None
306
219
 
307
220
    # Log File
308
221
    try:
398
311
 
399
312
        # Logging
400
313
        logging.error('%s\n%s'%(str(msg), tb))
401
 
        # Error messages are only displayed is the user is NOT a student,
402
 
        # or if there has been a problem logging the error message
403
 
        show_errors = (not publicmode) and ((login and \
404
 
                            str(role) != "student") or logfail)
 
314
 
405
315
        req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"                 
406
316
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">                                      
407
317
<html xmlns="http://www.w3.org/1999/xhtml">
408
318
<head><title>IVLE Internal Server Error</title></head>
409
319
<body>
410
320
<h1>IVLE Internal Server Error""")
411
 
        if (show_errors):
412
 
            if (codename is not None
413
 
                        and httpcode != mod_python.apache.HTTP_INTERNAL_SERVER_ERROR):
414
 
                req.write(": %s" % cgi.escape(codename))
415
 
        
 
321
        if (codename is not None
 
322
            and httpcode != apache.HTTP_INTERNAL_SERVER_ERROR):
 
323
            req.write(": %s" % cgi.escape(codename))
416
324
        req.write("""</h1>
417
325
<p>An error has occured which is the fault of the IVLE developers or
418
 
administration. The developers have been notified.</p>
 
326
administration.</p>
419
327
""")
420
 
        if (show_errors):
421
 
            if msg is not None:
422
 
                req.write("<p>%s</p>\n" % cgi.escape(msg))
423
 
            if httpcode is not None:
424
 
                req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
425
 
            req.write("""
426
 
    <p>Please report this to <a href="mailto:%s">%s</a> (the system
427
 
    administrator). Include the following information:</p>
428
 
    """ % (cgi.escape(admin_email), cgi.escape(admin_email)))
 
328
        if msg is not None:
 
329
            req.write("<p>%s</p>\n" % cgi.escape(msg))
 
330
        if httpcode is not None:
 
331
            req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
 
332
        req.write("""
 
333
<p>Please report this to <a href="mailto:%s">%s</a> (the system
 
334
administrator). Include the following information:</p>
 
335
""" % (cgi.escape(admin_email), cgi.escape(admin_email)))
429
336
 
430
 
            req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
431
 
            if logfail:
432
 
                req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
433
 
                    %cgi.escape(logfile))
 
337
        req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
 
338
        if logfail:
 
339
            req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
 
340
                %cgi.escape(logfile))
434
341
        req.write("</body></html>")