index d73d7d86f30e826286c619a191030ed91b438c73..e2a7d4b826475d92013bd71133bba8e63d007270 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: ZRoundup.py,v 1.3 2001-12-12 23:55:00 richard Exp $
+# $Id: ZRoundup.py,v 1.23 2008-02-07 01:03:39 richard Exp $
#
''' ZRoundup module - exposes the roundup web interface to Zope
-This frontend works by providing a thin layer that sits between Zope and the regular CGI
-interface of roundup, providing the web frontend with the minimum of effort.
+This frontend works by providing a thin layer that sits between Zope and the
+regular CGI interface of roundup, providing the web frontend with the minimum
+of effort.
-This means that the regular CGI interface does all authentication quite independently of
-Zope.
-
-It also means that any requests which specify :filter, :columns or :sort _must_ be done
-using a GET, so that this interface can re-parse the QUERY_STRING. Zope interprets the
-':' as a special character, and the special args are lost to it.
+This means that the regular CGI interface does all authentication quite
+independently of Zope. The roundup code is kept in memory though, and it
+runs in the same server as all your other Zope stuff, so it does have _some_
+advantages over regular CGI :)
'''
+
+import urlparse
+
from Globals import InitializeClass, HTMLFile
from OFS.SimpleItem import Item
from OFS.PropertyManager import PropertyManager
-from Acquisition import Implicit
+from Acquisition import Explicit, Implicit
from Persistence import Persistent
from AccessControl import ClassSecurityInfo
from AccessControl import ModuleSecurityInfo
modulesecurity = ModuleSecurityInfo()
import roundup.instance
-from roundup import cgi_client
+from roundup.cgi import client
-modulesecurity.declareProtected('View management screens', 'manage_addZRoundupForm')
+modulesecurity.declareProtected('View management screens',
+ 'manage_addZRoundupForm')
manage_addZRoundupForm = HTMLFile('dtml/manage_addZRoundupForm', globals())
modulesecurity.declareProtected('Add Z Roundups', 'manage_addZRoundup')
def end_headers(self):
# not needed - the RESPONSE object handles this internally on write()
pass
+ def start_response(self, headers, response):
+ self.send_response(response)
+ for key, value in headers:
+ self.send_header(key, value)
+ self.end_headers()
class FormItem:
'''Make a Zope form item look like a cgi.py one
self.value = value
if hasattr(self.value, 'filename'):
self.filename = self.value.filename
- self.file = self.value
+ self.value = self.value.read()
class FormWrapper:
'''Make a Zope form dict look like a cgi.py one
'''
def __init__(self, form):
- self.form = form
+ self.__form = form
def __getitem__(self, item):
- return FormItem(self.form[item])
+ entry = self.__form[item]
+ if isinstance(entry, type([])):
+ entry = map(FormItem, entry)
+ else:
+ entry = FormItem(entry)
+ return entry
+ def __iter__(self):
+ return iter(self.__form)
+ def getvalue(self, key, default=None):
+ if self.__form.has_key(key):
+ return self.__form[key]
+ else:
+ return default
def has_key(self, item):
- return self.form.has_key(item)
+ return self.__form.has_key(item)
def keys(self):
- return self.form.keys()
+ return self.__form.keys()
+
+ def __repr__(self):
+ return '<ZRoundup.FormWrapper %r>'%self.__form
class ZRoundup(Item, PropertyManager, Implicit, Persistent):
- '''An instance of this class provides an interface between Zope and roundup for one
- roundup instance
+ '''An instance of this class provides an interface between Zope and
+ roundup for one roundup instance
'''
meta_type = 'Z Roundup'
security = ClassSecurityInfo()
icon = "misc_/ZRoundup/icon"
- security.declarePrivate('_opendb')
- def _opendb(self):
+ security.declarePrivate('roundup_opendb')
+ def roundup_opendb(self):
'''Open the roundup instance database for a transaction.
'''
- instance = roundup.instance.open(self.instance_home)
+ tracker = roundup.instance.open(self.instance_home)
request = RequestWrapper(self.REQUEST['RESPONSE'])
env = self.REQUEST.environ
- env['INSTANCE_NAME'] = self.id
- if env['REQUEST_METHOD'] == 'GET':
- # force roundup to re-parse the request because Zope fiddles
- # with it and we lose all the :filter, :columns, etc goodness
- form = None
- else:
- form = FormWrapper(self.REQUEST.form)
- return instance.Client(instance, request, env, form)
+
+ # figure out the path components to set
+ url = urlparse.urlparse( self.absolute_url() )
+ path = url[2]
+ path_components = path.split( '/' )
+
+ # special case when roundup is '/' in this virtual host,
+ if path == "/" :
+ env['SCRIPT_NAME'] = "/"
+ env['TRACKER_NAME'] = ''
+ else :
+ # all but the last element is the path
+ env['SCRIPT_NAME'] = '/'.join( path_components[:-1] )
+ # the last element is the name
+ env['TRACKER_NAME'] = path_components[-1]
+
+ form = FormWrapper(self.REQUEST.form)
+ if hasattr(tracker, 'Client'):
+ return tracker.Client(tracker, request, env, form)
+ return client.Client(tracker, request, env, form)
security.declareProtected('View', 'index_html')
def index_html(self):
'''Alias index_html to roundup's index
'''
- client = self._opendb()
+ # Redirect misdirected requests -- bugs 558867 , 565992
+ # PATH_INFO, as defined by the CGI spec, has the *real* request path
+ orig_path = self.REQUEST.environ['PATH_INFO']
+ if orig_path[-1] != '/' :
+ url = urlparse.urlparse( self.absolute_url() )
+ url = list( url ) # make mutable
+ url[2] = url[2]+'/' # patch
+ url = urlparse.urlunparse( url ) # reassemble
+ RESPONSE = self.REQUEST.RESPONSE
+ RESPONSE.setStatus( "MovedPermanently" ) # 301
+ RESPONSE.setHeader( "Location" , url )
+ return RESPONSE
+
+ client = self.roundup_opendb()
# fake the path that roundup should use
client.split_path = ['index']
return client.main()
def __getitem__(self, item):
'''All other URL accesses are passed throuh to roundup
'''
+ return PathElement(self, item).__of__(self)
+
+class PathElement(Item, Implicit):
+ def __init__(self, zr, path):
+ self.zr = zr
+ self.path = path
+
+ def __getitem__(self, item):
+ ''' Get a subitem.
+ '''
+ return PathElement(self.zr, self.path + '/' + item).__of__(self)
+
+ def index_html(self, REQUEST=None):
+ ''' Actually call through to roundup to handle the request.
+ '''
try:
- client = self._opendb()
+ client = self.zr.roundup_opendb()
# fake the path that roundup should use
- client.split_path = [item]
+ client.path = self.path
# and call roundup to do something
client.main()
return ''
- except cgi_client.NotFound:
- raise 'NotFound', self.REQUEST.URL
+ except client.NotFound:
+ raise 'NotFound', REQUEST.URL
pass
except:
import traceback
traceback.print_exc()
# all other exceptions in roundup are valid
raise
- raise KeyError, item
-
InitializeClass(ZRoundup)
modulesecurity.apply(globals())
-#
-# $Log: not supported by cvs2svn $
-# Revision 1.2 2001/12/12 23:33:58 richard
-# added some implementation notes
-#
-# Revision 1.1 2001/12/12 23:27:13 richard
-# Added a Zope frontend for roundup.
-#
-#
-#
# vim: set filetype=python ts=4 sw=4 et si