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

« back to all changes in this revision

Viewing changes to ivle/dispatch/__init__.py

  • Committer: mattgiuca
  • Date: 2008-01-29 02:57:10 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:322
Added doc/setup - a setup guide specific to our configuration. This is the
result of my successfully configuring IVLE on a production server.

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
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
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
 
"""
28
 
 
29
 
import sys
30
 
import os
31
 
import os.path
32
 
import urllib
33
 
import cgi
34
 
import traceback
35
 
import logging
36
 
import socket
37
 
import time
38
 
 
39
 
import mod_python
40
 
import routes
41
 
 
42
 
from ivle import util
43
 
import ivle.conf
44
 
from ivle.dispatch.request import Request
45
 
import ivle.webapp.security
46
 
from ivle.webapp.base.plugins import ViewPlugin, PublicViewPlugin
47
 
from ivle.webapp.errors import HTTPError, Unauthorized
48
 
 
49
 
def generate_route_mapper(view_plugins, attr):
50
 
    """
51
 
    Build a Mapper object for doing URL matching using 'routes', based on the
52
 
    given plugin registry.
53
 
    """
54
 
    m = routes.Mapper(explicit=True)
55
 
    for plugin in view_plugins:
56
 
        # Establish a URL pattern for each element of plugin.urls
57
 
        assert hasattr(plugin, 'urls'), "%r does not have any urls" % plugin 
58
 
        for url in getattr(plugin, attr):
59
 
            routex = url[0]
60
 
            view_class = url[1]
61
 
            kwargs_dict = url[2] if len(url) >= 3 else {}
62
 
            m.connect(routex, view=view_class, **kwargs_dict)
63
 
    return m
64
 
 
65
 
def handler(req):
66
 
    """Handles a request which may be to anywhere in the site except media.
67
 
    Intended to be called by mod_python, as a handler.
68
 
 
69
 
    req: An Apache request object.
70
 
    """
71
 
    # Make the request object into an IVLE request which can be passed to apps
72
 
    apachereq = req
73
 
    try:
74
 
        req = Request(req)
75
 
    except Exception:
76
 
        # Pass the apachereq to error reporter, since ivle req isn't created
77
 
        # yet.
78
 
        handle_unknown_exception(apachereq, *sys.exc_info())
79
 
        # Tell Apache not to generate its own errors as well
80
 
        return mod_python.apache.OK
81
 
 
82
 
    # Run the main handler, and catch all exceptions
83
 
    try:
84
 
        return handler_(req, apachereq)
85
 
    except mod_python.apache.SERVER_RETURN:
86
 
        # An apache error. We discourage these, but they might still happen.
87
 
        # Just raise up.
88
 
        raise
89
 
    except Exception:
90
 
        handle_unknown_exception(req, *sys.exc_info())
91
 
        # Tell Apache not to generate its own errors as well
92
 
        return mod_python.apache.OK
93
 
 
94
 
def handler_(req, apachereq):
95
 
    """
96
 
    Nested handler function. May raise exceptions. The top-level handler is
97
 
    just used to catch exceptions.
98
 
    Takes both an IVLE request and an Apache req.
99
 
    """
100
 
    # Hack? Try and get the user login early just in case we throw an error
101
 
    # (most likely 404) to stop us seeing not logged in even when we are.
102
 
    if not req.publicmode:
103
 
        user = ivle.webapp.security.get_user_details(req)
104
 
 
105
 
        # Don't set the user if it is disabled or hasn't accepted the ToS.
106
 
        if user and user.valid:
107
 
            req.user = user
108
 
 
109
 
    conf = ivle.config.Config()
110
 
    req.config = conf
111
 
 
112
 
    if req.publicmode:
113
 
        req.mapper = generate_route_mapper(conf.plugin_index[PublicViewPlugin],
114
 
                                           'public_urls')
115
 
    else:
116
 
        req.mapper = generate_route_mapper(conf.plugin_index[ViewPlugin],
117
 
                                           'urls')
118
 
 
119
 
    matchdict = req.mapper.match(req.uri)
120
 
    if matchdict is not None:
121
 
        viewcls = matchdict['view']
122
 
        # Get the remaining arguments, less 'view', 'action' and 'controller'
123
 
        # (The latter two seem to be built-in, and we don't want them).
124
 
        kwargs = matchdict.copy()
125
 
        del kwargs['view']
126
 
        try:
127
 
            # Instantiate the view, which should be a BaseView class
128
 
            view = viewcls(req, **kwargs)
129
 
 
130
 
            # Check that the request (mainly the user) is permitted to access
131
 
            # the view.
132
 
            if not view.authorize(req):
133
 
                raise Unauthorized()
134
 
            # Render the output
135
 
            view.render(req)
136
 
        except HTTPError, e:
137
 
            # A view explicitly raised an HTTP error. Respect it.
138
 
            req.status = e.code
139
 
 
140
 
            # Try to find a custom error view.
141
 
            if hasattr(viewcls, 'get_error_view'):
142
 
                errviewcls = viewcls.get_error_view(e)
143
 
            else:
144
 
                errviewcls = None
145
 
 
146
 
            if errviewcls:
147
 
                errview = errviewcls(req, e)
148
 
                errview.render(req)
149
 
                return req.OK
150
 
            elif e.message:
151
 
                req.write(e.message)
152
 
                return req.OK
153
 
            else:
154
 
                return e.code
155
 
        except Exception, e:
156
 
            # A non-HTTPError appeared. We have an unknown exception. Panic.
157
 
            handle_unknown_exception(req, *sys.exc_info())
158
 
            return req.OK
159
 
        else:
160
 
            req.store.commit()
161
 
            return req.OK
162
 
    else:
163
 
        return req.HTTP_NOT_FOUND # TODO: Prettify.
164
 
 
165
 
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):
166
 
    """
167
 
    Given an exception that has just been thrown from IVLE, print its details
168
 
    to the request.
169
 
    This is a full handler. It assumes nothing has been written, and writes a
170
 
    complete HTML page.
171
 
    req: May be EITHER an IVLE req or an Apache req.
172
 
    The handler code may pass an apache req if an exception occurs before
173
 
    the IVLE request is created.
174
 
    """
175
 
    req.content_type = "text/html"
176
 
    logfile = os.path.join(ivle.conf.log_path, 'ivle_error.log')
177
 
    logfail = False
178
 
    # For some reason, some versions of mod_python have "_server" instead of
179
 
    # "main_server". So we check for both.
180
 
    try:
181
 
        admin_email = mod_python.apache.main_server.server_admin
182
 
    except AttributeError:
183
 
        try:
184
 
            admin_email = mod_python.apache._server.server_admin
185
 
        except AttributeError:
186
 
            admin_email = ""
187
 
    try:
188
 
        httpcode = exc_value.httpcode
189
 
        req.status = httpcode
190
 
    except AttributeError:
191
 
        httpcode = None
192
 
        req.status = mod_python.apache.HTTP_INTERNAL_SERVER_ERROR
193
 
    try:
194
 
        publicmode = req.publicmode
195
 
    except AttributeError:
196
 
        publicmode = True
197
 
    try:
198
 
        login = req.user.login
199
 
    except AttributeError:
200
 
        login = None
201
 
    try:
202
 
        role = req.user.role
203
 
    except AttributeError:
204
 
        role = None
205
 
 
206
 
    # Log File
207
 
    try:
208
 
        for h in logging.getLogger().handlers:
209
 
            logging.getLogger().removeHandler(h)
210
 
        logging.basicConfig(level=logging.INFO,
211
 
            format='%(asctime)s %(levelname)s: ' +
212
 
                '(HTTP: ' + str(req.status) +
213
 
                ', Ref: ' + str(login) + '@' +
214
 
                str(socket.gethostname()) + str(req.uri) +
215
 
                ') %(message)s',
216
 
            filename=logfile,
217
 
            filemode='a')
218
 
    except IOError:
219
 
        logfail = True
220
 
    logging.debug('Logging Unhandled Exception')
221
 
 
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
224
 
    # correctly).
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
228
 
    # traceback).
229
 
    # We also need to special-case IVLEJailError, as we can get another
230
 
    # almost-exception out of it.
231
 
 
232
 
    codename, msg = None, None
233
 
 
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)
238
 
    else:
239
 
        try:
240
 
            codename, msg = req.get_http_codename(httpcode)
241
 
        except AttributeError:
242
 
            pass
243
 
        # Override the default message with the supplied one,
244
 
        # if available.
245
 
        if hasattr(exc_value, 'message') and exc_value.message is not None:
246
 
            msg = exc_value.message
247
 
            # Prepend the exception type
248
 
            if exc_type != util.IVLEError:
249
 
                msg = exc_type.__name__ + ": " + repr(msg)
250
 
 
251
 
        tb = ''.join(traceback.format_exception(exc_type, exc_value,
252
 
                                                exc_traceback))
253
 
 
254
 
    # Logging
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"                 
261
 
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">                                      
262
 
<html xmlns="http://www.w3.org/1999/xhtml">
263
 
<head><title>IVLE Internal Server Error</title></head>
264
 
<body>
265
 
<h1>IVLE Internal Server Error""")
266
 
    if (show_errors):
267
 
        if (codename is not None
268
 
                    and httpcode != mod_python.apache.HTTP_INTERNAL_SERVER_ERROR):
269
 
            req.write(": %s" % cgi.escape(codename))
270
 
 
271
 
    req.write("""</h1>
272
 
<p>An error has occured which is the fault of the IVLE developers or
273
 
administration. The developers have been notified.</p>
274
 
""")
275
 
    if (show_errors):
276
 
        if msg is not None:
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)
280
 
        req.write("""
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)))
284
 
 
285
 
        req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
286
 
        if logfail:
287
 
            req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
288
 
                %cgi.escape(logfile))
289
 
    req.write("</body></html>")