1 # mod_python interface for Roundup Issue Tracker
2 #
3 # This module is free software, you may redistribute it
4 # and/or modify under the same terms as Python.
5 #
6 # This module provides Roundup Web User Interface
7 # using mod_python Apache module. Initially written
8 # with python 2.3.3, mod_python 3.1.3, roundup 0.7.0.
9 #
10 # This module operates with only one tracker
11 # and must be placed in the tracker directory.
12 #
13 # History (most recent first):
14 # 11-jul-2004 [als] added 'TrackerLanguage' option;
15 # pass message translator to the tracker client instance
16 # 04-jul-2004 [als] tracker lookup moved from module global to request handler;
17 # use PythonOption TrackerHome (configured in apache)
18 # to open the tracker
19 # 06-may-2004 [als] use cgi.FieldStorage from Python library
20 # instead of mod_python FieldStorage
21 # 29-apr-2004 [als] created
23 __version__ = "$Revision: 1.6 $"[11:-2]
24 __date__ = "$Date: 2006-11-09 00:36:21 $"[7:-2]
26 import cgi
27 import os
29 from mod_python import apache
31 import roundup.instance
32 from roundup.cgi import TranslationService
34 class Headers(dict):
36 """HTTP headers wrapper"""
38 def __init__(self, headers):
39 """Initialize with `apache.table`"""
40 super(Headers, self).__init__(headers)
41 self.getheader = self.get
43 class Request(object):
45 """`apache.Request` object wrapper providing roundup client interface"""
47 def __init__(self, request):
48 """Initialize with `apache.Request` object"""
49 self._req = request
50 # .headers.getheader()
51 self.headers = Headers(request.headers_in)
52 # .wfile.write()
53 self.wfile = self._req
55 def start_response(self, headers, response):
56 self.send_response(response)
57 for key, value in headers:
58 self.send_header(key, value)
59 self.end_headers()
61 def send_response(self, response_code):
62 """Set HTTP response code"""
63 self._req.status = response_code
65 def send_header(self, name, value):
66 """Set output header"""
67 # value may be an instance of roundup.cgi.exceptions.HTTPException
68 value = str(value)
69 # XXX default content_type is "text/plain",
70 # and ain't overrided by "Content-Type" header
71 if name == "Content-Type":
72 self._req.content_type = value
73 else:
74 self._req.headers_out.add(name, value)
76 def end_headers(self):
77 """NOOP. There aint no such thing as 'end_headers' in mod_python"""
78 pass
80 def handler(req):
81 """HTTP request handler"""
82 _options = req.get_options()
83 _home = _options.get("TrackerHome")
84 _lang = _options.get("TrackerLanguage")
85 _timing = _options.get("TrackerTiming", "no")
86 if _timing.lower() in ("no", "false"):
87 _timing = ""
88 _debug = _options.get("TrackerDebug", "no")
89 _debug = _debug.lower() not in ("no", "false")
90 if not (_home and os.path.isdir(_home)):
91 apache.log_error(
92 "PythonOption TrackerHome missing or invalid for %(uri)s"
93 % {'uri': req.uri})
94 return apache.HTTP_INTERNAL_SERVER_ERROR
95 _tracker = roundup.instance.open(_home, not _debug)
96 # create environment
97 # Note: cookies are read from HTTP variables, so we need all HTTP vars
98 req.add_common_vars()
99 _env = dict(req.subprocess_env)
100 # XXX classname must be the first item in PATH_INFO. roundup.cgi does:
101 # path = string.split(os.environ.get('PATH_INFO', '/'), '/')
102 # os.environ['PATH_INFO'] = string.join(path[2:], '/')
103 # we just remove the first character ('/')
104 _env["PATH_INFO"] = req.path_info[1:]
105 if _timing:
106 _env["CGI_SHOW_TIMING"] = _timing
107 _form = cgi.FieldStorage(req, environ=_env)
108 _client = _tracker.Client(_tracker, Request(req), _env, _form,
109 translator=TranslationService.get_translation(_lang,
110 tracker_home=_home))
111 _client.main()
112 return apache.OK
114 # vim: set et sts=4 sw=4 :