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

« back to all changes in this revision

Viewing changes to www/dispatch/__init__.py

  • Committer: chadnickbok
  • Date: 2009-01-13 05:33:58 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1108
Updated the settings page to require the old password
when updating the password. Note that this field
is not shown when using ldap authentication

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE
 
2
# Copyright (C) 2007-2008 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
# 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
 
 
29
import mod_python
 
30
from mod_python import apache, Cookie
 
31
 
 
32
import sys
 
33
import os
 
34
import os.path
 
35
import urllib
 
36
 
 
37
import conf
 
38
import conf.apps
 
39
import conf.conf
 
40
import apps
 
41
 
 
42
from request import Request
 
43
import html
 
44
import cgi
 
45
import login
 
46
from common import (util, forumutil)
 
47
import traceback
 
48
import plugins.console
 
49
import logging
 
50
import socket
 
51
import time
 
52
 
 
53
def handler(req):
 
54
    """Handles a request which may be to anywhere in the site except media.
 
55
    Intended to be called by mod_python, as a handler.
 
56
 
 
57
    req: An Apache request object.
 
58
    """
 
59
    # Make the request object into an IVLE request which can be passed to apps
 
60
    apachereq = req
 
61
    try:
 
62
        req = Request(req, html.write_html_head)
 
63
    except Exception:
 
64
        # Pass the apachereq to error reporter, since ivle req isn't created
 
65
        # yet.
 
66
        handle_unknown_exception(apachereq, *sys.exc_info())
 
67
        # Tell Apache not to generate its own errors as well
 
68
        return apache.OK
 
69
 
 
70
    # Run the main handler, and catch all exceptions
 
71
    try:
 
72
        return handler_(req, apachereq)
 
73
    except mod_python.apache.SERVER_RETURN:
 
74
        # An apache error. We discourage these, but they might still happen.
 
75
        # Just raise up.
 
76
        raise
 
77
    except Exception:
 
78
        handle_unknown_exception(req, *sys.exc_info())
 
79
        # Tell Apache not to generate its own errors as well
 
80
        return apache.OK
 
81
 
 
82
def handler_(req, apachereq):
 
83
    """
 
84
    Nested handler function. May raise exceptions. The top-level handler is
 
85
    just used to catch exceptions.
 
86
    Takes both an IVLE request and an Apache req.
 
87
    """
 
88
    # Hack? Try and get the user login early just in case we throw an error
 
89
    # (most likely 404) to stop us seeing not logged in even when we are.
 
90
    if not req.publicmode:
 
91
        req.user = login.get_user_details(req)
 
92
 
 
93
    # Check req.app to see if it is valid. 404 if not.
 
94
    if req.app is not None and req.app not in conf.apps.app_url:
 
95
        req.throw_error(Request.HTTP_NOT_FOUND,
 
96
            "There is no application called %s." % repr(req.app))
 
97
 
 
98
    # Special handling for public mode - only allow the public app, call it
 
99
    # and get out.
 
100
    # NOTE: This will not behave correctly if the public app uses
 
101
    # write_html_head_foot, but "serve" does not.
 
102
    if req.publicmode:
 
103
        if req.app != conf.apps.public_app:
 
104
            req.throw_error(Request.HTTP_FORBIDDEN,
 
105
                "This application is not available on the public site.")
 
106
        app = conf.apps.app_url[conf.apps.public_app]
 
107
        apps.call_app(app.dir, req)
 
108
        return req.OK
 
109
 
 
110
    # app is the App object for the chosen app
 
111
    if req.app is None:
 
112
        app = conf.apps.app_url[conf.apps.default_app]
 
113
    else:
 
114
        app = conf.apps.app_url[req.app]
 
115
 
 
116
    # Check if app requires auth. If so, perform authentication and login.
 
117
    # This will either return a User object, None, or perform a redirect
 
118
    # which we will not catch here.
 
119
    if app.requireauth:
 
120
        req.user = login.login(req)
 
121
        logged_in = req.user is not None
 
122
    else:
 
123
        req.user = login.get_user_details(req)
 
124
        logged_in = True
 
125
 
 
126
    if logged_in:
 
127
        # Keep the user's session alive by writing to the session object.
 
128
        # req.get_session().save()
 
129
        # Well, it's a fine idea, but it creates considerable grief in the
 
130
        # concurrent update department, so instead, we'll just make the
 
131
        # sessions not time out.
 
132
        req.get_session().unlock()
 
133
 
 
134
        # If user did not specify an app, HTTP redirect to default app and
 
135
        # exit.
 
136
        if req.app is None:
 
137
            req.throw_redirect(util.make_path(conf.apps.default_app))
 
138
 
 
139
        # Set the default title to the app's tab name, if any. Otherwise URL
 
140
        # name.
 
141
        if app.name is not None:
 
142
            req.title = app.name
 
143
        else:
 
144
            req.title = req.app
 
145
 
 
146
        # Call the specified app with the request object
 
147
        apps.call_app(app.dir, req)
 
148
 
 
149
    # if not logged in, login.login will have written the login box.
 
150
    # Just clean up and exit.
 
151
 
 
152
    # MAKE SURE we write the HTTP (and possibly HTML) header. This
 
153
    # wouldn't happen if nothing else ever got written, so we have to make
 
154
    # sure.
 
155
    req.ensure_headers_written()
 
156
 
 
157
    # When done, write out the HTML footer if the app has requested it
 
158
    if req.write_html_head_foot:
 
159
        # Show the console if required
 
160
        if logged_in and app.useconsole:
 
161
            plugins.console.present(req, windowpane=True)
 
162
        html.write_html_foot(req)
 
163
 
 
164
    # Note: Apache will not write custom HTML error messages here.
 
165
    # Use req.throw_error to do that.
 
166
    return req.OK
 
167
 
 
168
def handle_unknown_exception(req, exc_type, exc_value, exc_traceback):
 
169
    """
 
170
    Given an exception that has just been thrown from IVLE, print its details
 
171
    to the request.
 
172
    This is a full handler. It assumes nothing has been written, and writes a
 
173
    complete HTML page.
 
174
    req: May be EITHER an IVLE req or an Apache req.
 
175
    IVLE reqs may have the HTML head/foot written (on a 400 error), but
 
176
    the handler code may pass an apache req if an exception occurs before
 
177
    the IVLE request is created.
 
178
    """
 
179
    req.content_type = "text/html"
 
180
    logfile = os.path.join(conf.conf.log_path, 'ivle_error.log')
 
181
    logfail = False
 
182
    # For some reason, some versions of mod_python have "_server" instead of
 
183
    # "main_server". So we check for both.
 
184
    try:
 
185
        admin_email = apache.main_server.server_admin
 
186
    except AttributeError:
 
187
        try:
 
188
            admin_email = apache._server.server_admin
 
189
        except AttributeError:
 
190
            admin_email = ""
 
191
    try:
 
192
        httpcode = exc_value.httpcode
 
193
        req.status = httpcode
 
194
    except AttributeError:
 
195
        httpcode = None
 
196
        req.status = apache.HTTP_INTERNAL_SERVER_ERROR
 
197
    try:
 
198
        login = req.user.login
 
199
    except AttributeError:
 
200
        login = None
 
201
 
 
202
    # Log File
 
203
    try:
 
204
        for h in logging.getLogger().handlers:
 
205
            logging.getLogger().removeHandler(h)
 
206
        logging.basicConfig(level=logging.INFO,
 
207
            format='%(asctime)s %(levelname)s: ' +
 
208
                '(HTTP: ' + str(req.status) +
 
209
                ', Ref: ' + str(login) + '@' +
 
210
                str(socket.gethostname()) + str(req.uri) +
 
211
                ') %(message)s',
 
212
            filename=logfile,
 
213
            filemode='a')
 
214
    except IOError:
 
215
        logfail = True
 
216
    logging.debug('Logging Unhandled Exception')
 
217
 
 
218
    # We handle 3 types of error.
 
219
    # IVLEErrors with 4xx response codes (client error).
 
220
    # IVLEErrors with 5xx response codes (handled server error).
 
221
    # Other exceptions (unhandled server error).
 
222
    # IVLEErrors should not have other response codes than 4xx or 5xx
 
223
    # (eg. throw_redirect should have been used for 3xx codes).
 
224
    # Therefore, that is treated as an unhandled error.
 
225
 
 
226
    if (exc_type == util.IVLEError and httpcode >= 400
 
227
        and httpcode <= 499):
 
228
        # IVLEErrors with 4xx response codes are client errors.
 
229
        # Therefore, these have a "nice" response (we even coat it in the IVLE
 
230
        # HTML wrappers).
 
231
        
 
232
        req.write_html_head_foot = True
 
233
        req.write_javascript_settings = False
 
234
        req.write('<div id="ivle_padding">\n')
 
235
        try:
 
236
            codename, msg = req.get_http_codename(httpcode)
 
237
        except AttributeError:
 
238
            codename, msg = None, None
 
239
        # Override the default message with the supplied one,
 
240
        # if available.
 
241
        if exc_value.message is not None:
 
242
            msg = exc_value.message
 
243
        if codename is not None:
 
244
            req.write("<h1>Error: %s</h1>\n" % cgi.escape(codename))
 
245
        else:
 
246
            req.write("<h1>Error</h1>\n")
 
247
        if msg is not None:
 
248
            req.write("<p>%s</p>\n" % cgi.escape(msg))
 
249
        else:
 
250
            req.write("<p>An unknown error occured.</p>\n")
 
251
        
 
252
        # Logging
 
253
        logging.info(str(msg))
 
254
        
 
255
        req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
 
256
        if logfail:
 
257
            req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
 
258
                %cgi.escape(logfile))
 
259
        req.write('</div>\n')
 
260
        html.write_html_foot(req)
 
261
    else:
 
262
        # A "bad" error message. We shouldn't get here unless IVLE
 
263
        # misbehaves (which is currently very easy, if things aren't set up
 
264
        # correctly).
 
265
        # Write the traceback.
 
266
        # If this is a non-4xx IVLEError, get the message and httpcode and
 
267
        # make the error message a bit nicer (but still include the
 
268
        # traceback).
 
269
        # We also need to special-case IVLEJailError, as we can get another
 
270
        # almost-exception out of it.
 
271
 
 
272
        codename, msg = None, None
 
273
 
 
274
        if exc_type is util.IVLEJailError:
 
275
            msg = exc_value.type_str + ": " + exc_value.message
 
276
            tb = 'Exception information extracted from IVLEJailError:\n'
 
277
            tb += urllib.unquote(exc_value.info)
 
278
        else:
 
279
            try:
 
280
                codename, msg = req.get_http_codename(httpcode)
 
281
            except AttributeError:
 
282
                pass
 
283
            # Override the default message with the supplied one,
 
284
            # if available.
 
285
            if hasattr(exc_value, 'message') and exc_value.message is not None:
 
286
                msg = exc_value.message
 
287
                # Prepend the exception type
 
288
                if exc_type != util.IVLEError:
 
289
                    msg = exc_type.__name__ + ": " + msg
 
290
 
 
291
            tb = ''.join(traceback.format_exception(exc_type, exc_value,
 
292
                                                    exc_traceback))
 
293
 
 
294
        # Logging
 
295
        logging.error('%s\n%s'%(str(msg), tb))
 
296
 
 
297
        req.write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"                 
 
298
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">                                      
 
299
<html xmlns="http://www.w3.org/1999/xhtml">
 
300
<head><title>IVLE Internal Server Error</title></head>
 
301
<body>
 
302
<h1>IVLE Internal Server Error""")
 
303
        if (codename is not None
 
304
            and httpcode != apache.HTTP_INTERNAL_SERVER_ERROR):
 
305
            req.write(": %s" % cgi.escape(codename))
 
306
        req.write("""</h1>
 
307
<p>An error has occured which is the fault of the IVLE developers or
 
308
administration.</p>
 
309
""")
 
310
        if msg is not None:
 
311
            req.write("<p>%s</p>\n" % cgi.escape(msg))
 
312
        if httpcode is not None:
 
313
            req.write("<p>(HTTP error code %d)</p>\n" % httpcode)
 
314
        req.write("""
 
315
<p>Please report this to <a href="mailto:%s">%s</a> (the system
 
316
administrator). Include the following information:</p>
 
317
""" % (cgi.escape(admin_email), cgi.escape(admin_email)))
 
318
 
 
319
        req.write("<pre>\n%s\n</pre>\n"%cgi.escape(tb))
 
320
        if logfail:
 
321
            req.write("<p>Warning: Could not open Error Log: '%s'</p>\n"
 
322
                %cgi.escape(logfile))
 
323
        req.write("</body></html>")