Improve the formatting of Quixote generated pages.

Introduce the errors.format_page() function and use it to generate
all HTML pages produced by Quixote.  It provides a single location
to "monkey-patch" if applications want to customize the look of the
pages.  Improve the wording of the messages on some of the error
pages.  Provide some basic CSS rules to make the pages look a little
more modern.  Use the HTML 5 doctype.
This commit is contained in:
Neil Schemenauer 2012-01-02 13:24:00 -06:00
parent 1940923eef
commit 7ed9542edd
3 changed files with 70 additions and 62 deletions

View File

@ -30,7 +30,8 @@ class PublishError(Exception):
status_code = 400 # bad request
title = "Publishing error"
description = "no description"
description = ("An error occured while generating the requested page. "
"For help, please contact the site administrator.")
def __init__(self, public_msg=None, private_msg=None):
self.public_msg = public_msg
@ -135,20 +136,68 @@ class MethodNotAllowedError(PublishError):
return 'Allowed methods are: %s' % allowed_methods
PAGE_TEMPLATE = htmltext('''\
<!DOCTYPE html>
<html>
<head>
<title>%(title)s</title>
<style type="text/css">
body {
font: 13px arial,helvetica,clean,sans-serif;
}
h1 {
font-size: 24px;
}
p {
width: 40em;
}
</style>
</head>
<body>
<h1>%(title)s</h1>
%(body)s
</body>
</html>
''')
def format_page(title, body):
"""Used for Quixote generated HTML pages. This function can be replaced to
ensure you application has a consistent look to web pages. Be aware
that this function should do a minimal amount of processing since it
can be called when the server encounters an error.
"""
return PAGE_TEMPLATE % dict(title=title, body=body)
ERROR_BODY = htmltext('''
<p>%(description)s</p>
<p>%(details)s</p>
''')
def format_error_page(title, description, details):
body = ERROR_BODY % dict(description=description, details=details)
return format_page(title=title, body=body)
# Error message to dispay for non-PublishError exception when
# DISPLAY_EXCEPTIONS is set to None. If DISPLAY_EXCEPTIONS is not
# None than a traceback will displayed.
INTERNAL_ERROR_MESSAGE = format_error_page(
title='Internal Server Error',
description=('An internal error occured while handling your page '
'request.'),
details=('The error has been logged but you may wish to contact the '
'server administrator and inform them of the time the error '
'occurred, and anything you might have done to trigger the '
'error.'))
def format_publish_error(exc):
"""(exc : PublishError) -> string
Format a PublishError exception as a web page.
"""
return htmltext("""\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
<head><title>Error: %s</title></head>
<body>
<p>%s</p>
<p>%s</p>
</body>
</html>
""") % (exc.title, exc.description, exc.format())
return format_error_page(title='Error: %s' % exc.title,
description=exc.description,
details=exc.format())

View File

@ -7,37 +7,13 @@ import urlparse
import cgitb
from quixote.errors import PublishError, MethodNotAllowedError, \
format_publish_error
format_publish_error, INTERNAL_ERROR_MESSAGE
from quixote import util
from quixote.config import Config
from quixote.http_response import HTTPResponse
from quixote.http_request import HTTPRequest
from quixote.logger import DefaultLogger
# Error message to dispay when DISPLAY_EXCEPTIONS in config file is not
# true. Note that SERVER_ADMIN must be fetched from the environment and
# plugged in here -- we can't do it now because the environment isn't
# really setup for us yet if running as a FastCGI script.
INTERNAL_ERROR_MESSAGE = """\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
<head><title>Internal Server Error</title></head>
<body>
<h1>Internal Server Error</h1>
<p>An internal error occurred while handling your request.</p>
<p>The server administrator should have been notified of the problem.
You may wish to contact the server administrator (%s) and inform them of
the time the error occurred, and anything you might have done to trigger
the error.</p>
<p>If you are the server administrator, more information may be
available in either the server's error log or Quixote's error log.</p>
</body>
</html>
"""
class Publisher:
"""
The core of Quixote and of any Quixote application. This class is
@ -205,9 +181,7 @@ class Publisher:
def _generate_internal_error(self, request):
admin = request.get_environ('SERVER_ADMIN',
"<i>email address unknown</i>")
return INTERNAL_ERROR_MESSAGE % admin
return INTERNAL_ERROR_MESSAGE
def _generate_plaintext_error(self, request, original_response,

View File

@ -245,20 +245,6 @@ class StaticDirectory(Directory):
self.file_class = self.FILE_CLASS
self.index_filenames = index_filenames
def _render_header(self, title):
r = TemplateIO(html=True)
r += htmltext('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 '
'Transitional//EN" '
'"http://www.w3.org/TR/REC-html40/loose.dtd">')
r += htmltext('<html>')
r += htmltext('<head><title>%s</title></head>') % title
r += htmltext('<body>')
r += htmltext("<h1>%s</h1>") % title
return r.getvalue()
def _render_footer(self):
return htmltext('</body></html>')
def _q_index(self):
"""
If directory listings are allowed, generate a simple HTML
@ -275,9 +261,9 @@ class StaticDirectory(Directory):
if (not isinstance(obj, StaticDirectory)
and hasattr(obj, '__call__')):
return obj()
r = TemplateIO(html=True)
if self.list_directory:
r += self._render_header('Index of %s' % quixote.get_path())
title = 'Index of %s' % quixote.get_path()
r = TemplateIO(html=True)
template = htmltext('<a href="%s">%s</a>%s\n')
r += htmltext('<pre>')
r += template % ('..', '..', '')
@ -288,13 +274,12 @@ class StaticDirectory(Directory):
marker = os.path.isdir(filepath) and "/" or ""
r += template % (urllib.quote(filename), filename, marker)
r += htmltext('</pre>')
r += self._render_footer()
body = r.getvalue()
else:
r += self._render_header('Directory listing denied')
r += htmltext('<p>This directory does not allow its contents '
'to be listed.</p>')
r += self._render_footer()
return r.getvalue()
title = 'Directory listing denied'
body = htmltext('<p>This directory does not allow its contents '
'to be listed.</p>')
return errors.format_page(title, body)
def _q_lookup(self, name):
"""