From 686ad3763df6183d8fabb8ccbeb7e0fb7bbc4e22 Mon Sep 17 00:00:00 2001 From: richard Date: Thu, 5 Sep 2002 00:37:09 +0000 Subject: [PATCH] moved git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1068 57a73879-2fb5-44c3-a270-3262357dd7e2 --- TODO.txt | 4 + ZTUtils/CHANGES.txt | 28 -- ZTUtils/HISTORY.txt | 57 ---- ZTUtils/SimpleTree.py | 57 ---- ZTUtils/Tree.py | 240 -------------- ZTUtils/Zope.py | 302 ------------------ doc/installation.txt | 80 +++-- roundup/backends/back_anydbm.py | 7 +- roundup/backends/back_gadfly.py | 7 +- .../cgi/PageTemplates}/.cvsignore | 0 .../cgi/PageTemplates/ComputedAttribute.py | 11 + .../cgi/PageTemplates}/Expressions.py | 146 +++------ roundup/cgi/PageTemplates/MultiMapping.py | 25 ++ .../cgi/PageTemplates}/PageTemplate.py | 12 +- .../cgi/PageTemplates}/PathIterator.py | 0 .../cgi/PageTemplates}/PythonExpr.py | 0 .../cgi/PageTemplates}/README.txt | 0 .../cgi/PageTemplates}/TALES.py | 3 +- .../cgi/PageTemplates}/__init__.py | 2 +- {TAL => roundup/cgi/TAL}/.cvsignore | 0 {TAL => roundup/cgi/TAL}/HTMLParser.py | 0 {TAL => roundup/cgi/TAL}/HTMLTALParser.py | 0 {TAL => roundup/cgi/TAL}/README.txt | 0 {TAL => roundup/cgi/TAL}/TALDefs.py | 0 {TAL => roundup/cgi/TAL}/TALGenerator.py | 0 {TAL => roundup/cgi/TAL}/TALInterpreter.py | 0 {TAL => roundup/cgi/TAL}/TALParser.py | 0 {TAL => roundup/cgi/TAL}/XMLParser.py | 11 +- {TAL => roundup/cgi/TAL}/__init__.py | 0 {TAL => roundup/cgi/TAL}/markupbase.py | 0 {ZTUtils => roundup/cgi/ZTUtils}/.cvsignore | 0 {ZTUtils => roundup/cgi/ZTUtils}/Batch.py | 12 +- {ZTUtils => roundup/cgi/ZTUtils}/Iterator.py | 2 +- {ZTUtils => roundup/cgi/ZTUtils}/__init__.py | 13 +- roundup/cgi/templating.py | 30 +- 35 files changed, 174 insertions(+), 875 deletions(-) delete mode 100644 ZTUtils/CHANGES.txt delete mode 100644 ZTUtils/HISTORY.txt delete mode 100644 ZTUtils/SimpleTree.py delete mode 100644 ZTUtils/Tree.py delete mode 100644 ZTUtils/Zope.py rename {PageTemplates => roundup/cgi/PageTemplates}/.cvsignore (100%) create mode 100644 roundup/cgi/PageTemplates/ComputedAttribute.py rename {PageTemplates => roundup/cgi/PageTemplates}/Expressions.py (67%) create mode 100644 roundup/cgi/PageTemplates/MultiMapping.py rename {PageTemplates => roundup/cgi/PageTemplates}/PageTemplate.py (96%) rename {PageTemplates => roundup/cgi/PageTemplates}/PathIterator.py (100%) rename {PageTemplates => roundup/cgi/PageTemplates}/PythonExpr.py (100%) rename {PageTemplates => roundup/cgi/PageTemplates}/README.txt (100%) rename {PageTemplates => roundup/cgi/PageTemplates}/TALES.py (99%) rename {PageTemplates => roundup/cgi/PageTemplates}/__init__.py (94%) rename {TAL => roundup/cgi/TAL}/.cvsignore (100%) rename {TAL => roundup/cgi/TAL}/HTMLParser.py (100%) rename {TAL => roundup/cgi/TAL}/HTMLTALParser.py (100%) rename {TAL => roundup/cgi/TAL}/README.txt (100%) rename {TAL => roundup/cgi/TAL}/TALDefs.py (100%) rename {TAL => roundup/cgi/TAL}/TALGenerator.py (100%) rename {TAL => roundup/cgi/TAL}/TALInterpreter.py (100%) rename {TAL => roundup/cgi/TAL}/TALParser.py (100%) rename {TAL => roundup/cgi/TAL}/XMLParser.py (91%) rename {TAL => roundup/cgi/TAL}/__init__.py (100%) rename {TAL => roundup/cgi/TAL}/markupbase.py (100%) rename {ZTUtils => roundup/cgi/ZTUtils}/.cvsignore (100%) rename {ZTUtils => roundup/cgi/ZTUtils}/Batch.py (95%) rename {ZTUtils => roundup/cgi/ZTUtils}/Iterator.py (98%) rename {ZTUtils => roundup/cgi/ZTUtils}/__init__.py (64%) diff --git a/TODO.txt b/TODO.txt index eb6482c..c707f7d 100644 --- a/TODO.txt +++ b/TODO.txt @@ -49,11 +49,15 @@ pending web: search "refinement" pending web: have roundup.cgi pick up instance config from the environment New templating TODO: +. move PageTempalates, TAL, ZTUtils into roundup.cgi and clean up . rewritten documentation (can come after the beta though so stuff is settled) +. modify cgitb to handle PageTemplate errors better . add :required to edit action active web: title is stoopid active hyperdb: full-text searching doesn't appear to match stuff in titles, even though they're supposed to be indexed... +active web: daemonify roundup-server (fork, logfile, pidfile) +active web: UNIX init.d script for roundup-server ongoing: any bugs diff --git a/ZTUtils/CHANGES.txt b/ZTUtils/CHANGES.txt deleted file mode 100644 index e2ad284..0000000 --- a/ZTUtils/CHANGES.txt +++ /dev/null @@ -1,28 +0,0 @@ -ZTUtils changes - - This file contains change information for the current release. - Change information for previous versions can be found in the - file HISTORY.txt. - - Version 1.5 - - Features Added - - - Added 'sequence_length' attribute to batches. - - - Under Python 2.2, Iterator both accepts and produces Python - iterator objects. - - - first() and last() methods allow you to tell whether the - current element is different from the next or previous - element. This is most useful when the sequence is sorted. - - Bugs Fixed - - - Handle both string and class Unauthorized exceptions. - - - Batch construction masked sequence errors, such as - Unauthorized. - - - Orphan defaulted to different values in different places. - diff --git a/ZTUtils/HISTORY.txt b/ZTUtils/HISTORY.txt deleted file mode 100644 index ee37155..0000000 --- a/ZTUtils/HISTORY.txt +++ /dev/null @@ -1,57 +0,0 @@ -ZTUtils history - - This file contains change information for previous versions of - ZTUtils. Change information for the current release can be found - in the file CHANGES.txt. - - - Version 1.1.3 - - Brown-bag bugfix release. - - Version 1.1.2 - - Bugs Fixed - - - Orphans defaulted to 3, which was confusing and out of sync - with DTML-In. - - - Orphan batches were broken. - - Version 1.1.1 - - Bugs Fixed - - - Python 1.5.2-incompatible changes crept in. - - Version 1.1.0 - - Features Added - - - TreeMakers have a setChildAccess() method that you can use - to control tree construction. Child nodes can be accessed - through either an attribute name or callback function. - Children fetched by attribute name can be filtered through a - callback function. - - - A new LazyFilter class allows you to filter a sequence using - Zope security and an optional filter callback function. The - security and filter tests are lazy, meaning they are - performed as late as possible. - - The optional 'skip' argument determines the reaction when - access to a sequence element is refused by the Zope security - policy. The default (None) is to raise the 'Unauthorized' - exception. If a string is passed, such elements are - skipped. If the string is non-empty, it is treated as a - permission name, and the element is skipped if the user - doesn't have that permission on the element. - - - The Zope versions of TreeMaker, SimpleTreeMaker, and Batch - now use LazyFilter. The TreeMakers have a setSkip() method - that can be used to set the 'skip' value. Batch has an - optional 'skip_unauthorized' argument that is passed to - LazyFilter as 'skip'. - - - Utility functions make_query(), url_query(), and - make_hidden_input() have been added. diff --git a/ZTUtils/SimpleTree.py b/ZTUtils/SimpleTree.py deleted file mode 100644 index ca32073..0000000 --- a/ZTUtils/SimpleTree.py +++ /dev/null @@ -1,57 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## -__doc__='''Simple Tree classes - -$Id: SimpleTree.py,v 1.1 2002-08-30 08:25:34 richard Exp $''' -__version__='$Revision: 1.1 $'[11:-2] - -from Tree import TreeMaker, TreeNode, b2a - -class SimpleTreeNode(TreeNode): - def branch(self): - if self.state == 0: - return {'link': None, 'img': '  '} - - if self.state < 0: - setst = 'expand' - exnum = self.aq_parent.expansion_number - img = 'pl' - else: - setst = 'collapse' - exnum = self.expansion_number - img = 'mi' - - base = self.aq_acquire('baseURL') - obid = self.id - pre = self.aq_acquire('tree_pre') - - return {'link': '?%s-setstate=%s,%s,%s#%s' % (pre, setst[0], - exnum, obid, obid), - 'img': '%s' % (base, img, setst)} - - -class SimpleTreeMaker(TreeMaker): - '''Generate Simple Trees''' - - def __init__(self, tree_pre="tree"): - self.tree_pre = tree_pre - - def node(self, object): - node = SimpleTreeNode() - node.object = object - node.id = b2a(self.getId(object)) - return node - - def markRoot(self, node): - node.tree_pre = self.tree_pre - node.baseURL = node.object.REQUEST['BASEPATH1'] diff --git a/ZTUtils/Tree.py b/ZTUtils/Tree.py deleted file mode 100644 index ea0b562..0000000 --- a/ZTUtils/Tree.py +++ /dev/null @@ -1,240 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## -__doc__='''Tree manipulation classes - -$Id: Tree.py,v 1.1 2002-08-30 08:25:34 richard Exp $''' -__version__='$Revision: 1.1 $'[11:-2] - -from Acquisition import Explicit -from ComputedAttribute import ComputedAttribute - -class TreeNode(Explicit): - __allow_access_to_unprotected_subobjects__ = 1 - state = 0 # leaf - height = 1 - size = 1 - def __init__(self): - self._child_list = [] - def _add_child(self, child): - 'Add a child which already has all of its children.' - self._child_list.append(child) - self.height = max(self.height, child.height + 1) - self.size = self.size + child.size - def flat(self): - 'Return a flattened preorder list of tree nodes' - items = [] - self.walk(items.append) - return items - def walk(self, f, data=None): - 'Preorder walk this tree, passing each node to a function' - if data is None: - f(self) - else: - f(self, data) - for child in self._child_list: - child.__of__(self).walk(f, data) - def _depth(self): - return self.aq_parent.depth + 1 - depth = ComputedAttribute(_depth, 1) - def __getitem__(self, index): - return self._child_list[index].__of__(self) - def __len__(self): - return len(self._child_list) - -_marker = [] - -class TreeMaker: - '''Class for mapping a hierachy of objects into a tree of nodes.''' - - __allow_access_to_unprotected_subobjects__ = 1 - - _id = 'tpId' - _values = 'tpValues' - _assume_children = 0 - _values_filter = None - _values_function = None - _expand_root = 1 - - def setChildAccess(self, attrname=_marker, filter=_marker, - function=_marker): - '''Set the criteria for fetching child nodes. - - Child nodes can be accessed through either an attribute name - or callback function. Children fetched by attribute name can - be filtered through a callback function. - ''' - if function is _marker: - self._values_function = None - if attrname is not _marker: - self._values = str(attrname) - if filter is not _marker: - self._values_filter = filter - else: - self._values_function = function - - def tree(self, root, expanded=None, subtree=0): - '''Create a tree from root, with specified nodes expanded. - - "expanded" must be false, true, or a mapping. - Each key of the mapping is the id of a top-level expanded - node, and each value is the "expanded" value for the - children of that node. - ''' - node = self.node(root) - child_exp = expanded - if not simple_type(expanded): - # Assume a mapping - expanded = expanded.has_key(node.id) - child_exp = child_exp.get(node.id) - if expanded or (not subtree and self._expand_root): - children = self.getChildren(root) - if children: - node.state = 1 # expanded - for child in children: - node._add_child(self.tree(child, child_exp, 1)) - elif self.hasChildren(root): - node.state = -1 # collapsed - if not subtree: - node.depth = 0 - if hasattr(self, 'markRoot'): - self.markRoot(node) - return node - - def node(self, object): - node = TreeNode() - node.object = object - node.id = b2a(self.getId(object)) - return node - - def getId(self, object): - id_attr = self._id - if hasattr(object, id_attr): - obid = getattr(object, id_attr) - if not simple_type(obid): obid = obid() - return obid - if hasattr(object, '_p_oid'): return str(object._p_oid) - return id(object) - - def hasChildren(self, object): - if self._assume_children: - return 1 - return self.getChildren(object) - - def getChildren(self, object): - if self._values_function is not None: - return self._values_function(object) - if self._values_filter and hasattr(object, 'aq_acquire'): - return object.aq_acquire(self._values, aqcallback, - self._values_filter)() - return getattr(object, self._values)() - -def simple_type(ob, - is_simple={type(''):1, type(0):1, type(0.0):1, - type(0L):1, type(None):1 }.has_key): - return is_simple(type(ob)) - -def aqcallback(self, inst, parent, name, value, filter): - return filter(self, inst, parent, name, value) - -from binascii import b2a_base64, a2b_base64 -import string -from string import split, join, translate - -a2u_map = string.maketrans('+/=', '-._') -u2a_map = string.maketrans('-._', '+/=') - -def b2a(s): - '''Encode a value as a cookie- and url-safe string. - - Encoded string use only alpahnumeric characters, and "._-". - ''' - s = str(s) - if len(s) <= 57: - return translate(b2a_base64(s)[:-1], a2u_map) - frags = [] - for i in range(0, len(s), 57): - frags.append(b2a_base64(s[i:i + 57])[:-1]) - return translate(join(frags, ''), a2u_map) - -def a2b(s): - '''Decode a b2a-encoded string.''' - s = translate(s, u2a_map) - if len(s) <= 76: - return a2b_base64(s) - frags = [] - for i in range(0, len(s), 76): - frags.append(a2b_base64(s[i:i + 76])) - return join(frags, '') - -def encodeExpansion(nodes): - '''Encode the expanded node ids of a tree into a string. - - Accepts a list of nodes, such as that produced by root.flat(). - Marks each expanded node with an expansion_number attribute. - Since node ids are encoded, the resulting string is safe for - use in cookies and URLs. - ''' - steps = [] - last_depth = -1 - n = 0 - for node in nodes: - if node.state <=0: continue - dd = last_depth - node.depth + 1 - last_depth = node.depth - if dd > 0: - steps.append('.' * dd) - steps.append(node.id) - node.expansion_number = n - n = n + 1 - return join(steps, ':') - -def decodeExpansion(s, nth=None): - '''Decode an expanded node map from a string. - - If nth is an integer, also return the (map, key) pair for the nth entry. - ''' - map = m = {} - mstack = [] - pop = 0 - nth_pair = None - if nth is not None: - nth_pair = (None, None) - for step in split(s, ':'): - if step[:1] == '.': - pop = len(step) - 1 - continue - if pop < 0: - mstack.append(m) - m[obid] = {} - m = m[obid] - elif map: - m[obid] = None - if len(step) == 0: - return map - obid = step - if pop > 0: - m = mstack[-pop] - del mstack[-pop:] - pop = -1 - if nth == 0: - nth_pair = (m, obid) - nth = None - elif nth is not None: - nth = nth - 1 - m[obid] = None - if nth == 0: - return map, (m, obid) - if nth_pair is not None: - return map, nth_pair - return map - diff --git a/ZTUtils/Zope.py b/ZTUtils/Zope.py deleted file mode 100644 index 1f84078..0000000 --- a/ZTUtils/Zope.py +++ /dev/null @@ -1,302 +0,0 @@ -############################################################################## -# -# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE -# -############################################################################## -__doc__='''Zope-specific versions of ZTUTils classes - -$Id: Zope.py,v 1.1 2002-08-30 08:25:34 richard Exp $''' -__version__='$Revision: 1.1 $'[11:-2] - -import sys, cgi, urllib, cgi -from Tree import encodeExpansion, decodeExpansion, TreeMaker -from SimpleTree import SimpleTreeMaker -from Batch import Batch -from Products.ZCatalog.Lazy import Lazy -from AccessControl import getSecurityManager -from string import split, join -from types import StringType, ListType, IntType, FloatType -from DateTime import DateTime - -try: - from AccessControl.ZopeGuards import guarded_getitem -except ImportError: - Unauthorized = 'Unauthorized' - def guarded_getitem(object, index): - v = object[index] - if getSecurityManager().validate(object, object, index, v): - return v - raise Unauthorized, 'unauthorized access to element %s' % `i` -else: - from AccessControl import Unauthorized - -class LazyFilter(Lazy): - # A LazyFilter that checks with the security policy - - def __init__(self, seq, test=None, skip=None): - self._seq=seq - self._data=[] - self._eindex=-1 - self._test=test - if not (skip is None or str(skip) == skip): - raise TypeError, 'Skip must be None or a string' - self._skip = skip - - def __getitem__(self,index): - data=self._data - try: s=self._seq - except AttributeError: return data[index] - - i=index - if i < 0: i=len(self)+i - if i < 0: raise IndexError, index - - ind=len(data) - if i < ind: return data[i] - ind=ind-1 - - test=self._test - e=self._eindex - skip = self._skip - while i > ind: - e = e + 1 - try: - try: v = guarded_getitem(s, e) - except Unauthorized, vv: - if skip is None: - self._eindex = e - msg = '(item %s): %s' % (index, vv) - raise Unauthorized, msg, sys.exc_info()[2] - skip_this = 1 - else: - skip_this = 0 - except IndexError: - del self._test - del self._seq - del self._eindex - raise IndexError, index - if skip_this: continue - if skip and not getSecurityManager().checkPermission(skip, v): - continue - if test is None or test(v): - data.append(v) - ind=ind+1 - self._eindex=e - return data[i] - -class TreeSkipMixin: - '''Mixin class to make trees test security, and allow - skipping of unauthorized objects. ''' - skip = None - def setSkip(self, skip): - self.skip = skip - return self - def getChildren(self, object): - return LazyFilter(self._getChildren(object), skip=self.skip) - -class TreeMaker(TreeSkipMixin, TreeMaker): - _getChildren = TreeMaker.getChildren - -class SimpleTreeMaker(TreeSkipMixin, SimpleTreeMaker): - _getChildren = SimpleTreeMaker.getChildren - def cookieTree(self, root_object, default_state=None): - '''Make a tree with state stored in a cookie.''' - tree_pre = self.tree_pre - state_name = '%s-state' % tree_pre - set_name = '%s-setstate' % tree_pre - - req = root_object.REQUEST - state = req.get(state_name) - if state: - setst = req.form.get(set_name) - if setst: - st, pn, expid = split(setst, ',') - state, (m, obid) = decodeExpansion(state, int(pn)) - if m is None: - pass - elif st == 'e': - if m[obid] is None: - m[obid] = {expid: None} - else: - m[obid][expid] = None - elif st == 'c' and m is not state and obid==expid: - del m[obid] - else: - state = decodeExpansion(state) - else: - state = default_state - tree = self.tree(root_object, state) - rows = tree.flat() - req.RESPONSE.setCookie(state_name, encodeExpansion(rows)) - return tree, rows - -# Make the Batch class test security, and let it skip unauthorized. -_Batch = Batch -class Batch(Batch): - def __init__(self, sequence, size, start=0, end=0, - orphan=0, overlap=0, skip_unauthorized=None): - sequence = LazyFilter(sequence, skip=skip_unauthorized) - _Batch.__init__(self, sequence, size, start, end, - orphan, overlap) - -# These functions are meant to be used together in templates that use -# trees or batches. For example, given a batch with a 'bstart' query -# argument, you would use "url_query(request, omit='bstart')" to get -# the base for the batching links, then append -# "make_query(bstart=batch.previous.first)" to one and -# "make_query(bstart=batch.end)" to the other. - -def make_query(*args, **kwargs): - '''Construct a URL query string, with marshalling markup. - - If there are positional arguments, they must be dictionaries. - They are combined with the dictionary of keyword arguments to form - a dictionary of query names and values. - - Query names (the keys) must be strings. Values may be strings, - integers, floats, or DateTimes, and they may also be lists or - namespaces containing these types. Names and string values - should not be URL-quoted. All arguments are marshalled with - complex_marshal(). - ''' - - d = {} - for arg in args: - d.update(arg) - d.update(kwargs) - - uq = urllib.quote - qlist = complex_marshal(d.items()) - for i in range(len(qlist)): - k, m, v = qlist[i] - qlist[i] = '%s%s=%s' % (uq(k), m, uq(str(v))) - - return join(qlist, '&') - -def make_hidden_input(*args, **kwargs): - '''Construct a set of hidden input elements, with marshalling markup. - - If there are positional arguments, they must be dictionaries. - They are combined with the dictionary of keyword arguments to form - a dictionary of query names and values. - - Query names (the keys) must be strings. Values may be strings, - integers, floats, or DateTimes, and they may also be lists or - namespaces containing these types. All arguments are marshalled with - complex_marshal(). - ''' - - d = {} - for arg in args: - d.update(arg) - d.update(kwargs) - - hq = cgi.escape - qlist = complex_marshal(d.items()) - for i in range(len(qlist)): - k, m, v = qlist[i] - qlist[i] = ('' - % (hq(k), m, hq(str(v)))) - - return join(qlist, '\n') - -def complex_marshal(pairs): - '''Add request marshalling information to a list of name-value pairs. - - Names must be strings. Values may be strings, - integers, floats, or DateTimes, and they may also be lists or - namespaces containing these types. - - The list is edited in place so that each (name, value) pair - becomes a (name, marshal, value) triple. The middle value is the - request marshalling string. Integer, float, and DateTime values - will have ":int", ":float", or ":date" as their marshal string. - Lists will be flattened, and the elements given ":list" in - addition to their simple marshal string. Dictionaries will be - flattened and marshalled using ":record". - ''' - i = len(pairs) - while i > 0: - i = i - 1 - k, v = pairs[i] - m = '' - sublist = None - if isinstance(v, StringType): - pass - elif hasattr(v, 'items'): - sublist = [] - for sk, sv in v.items(): - sm = simple_marshal(sv) - sublist.append(('%s.%s' % (k, sk), '%s:record' % sm, sv)) - elif isinstance(v, ListType): - sublist = [] - for sv in v: - sm = simple_marshal(sv) - sublist.append((k, '%s:list' % sm, sv)) - else: - m = simple_marshal(v) - if sublist is None: - pairs[i] = (k, m, v) - else: - pairs[i:i + 1] = sublist - - return pairs - -def simple_marshal(v): - if isinstance(v, StringType): - return '' - if isinstance(v, IntType): - return ':int' - if isinstance(v, FloatType): - return ':float' - if isinstance(v, DateTime): - return ':date' - return '' - -def url_query(request, req_name="URL", omit=None): - '''Construct a URL with a query string, using the current request. - - request: the request object - req_name: the name, such as "URL1" or "BASEPATH1", to get from request - omit: sequence of name of query arguments to omit. If a name - contains a colon, it is treated literally. Otherwise, it will - match each argument name that starts with the name and a period or colon. - ''' - - base = request[req_name] - qs = request.get('QUERY_STRING', '') - - if qs and omit: - qsparts = split(qs, '&') - - if isinstance(omit, StringType): - omits = {omit: None} - else: - omits = {} - for name in omit: - omits[name] = None - omitted = omits.has_key - - unq = urllib.unquote - for i in range(len(qsparts)): - name = unq(split(qsparts[i], '=', 1)[0]) - if omitted(name): - qsparts[i] = '' - name = split(name, ':', 1)[0] - if omitted(name): - qsparts[i] = '' - name = split(name, '.', 1)[0] - if omitted(name): - qsparts[i] = '' - - qs = join(filter(None, qsparts), '&') - - # We alway append '?' since arguments will be appended to the URL - return '%s?%s' % (base, qs) diff --git a/doc/installation.txt b/doc/installation.txt index f98e776..5ab4af2 100644 --- a/doc/installation.txt +++ b/doc/installation.txt @@ -2,7 +2,7 @@ Installing Roundup ================== -:Version: $Revision: 1.19 $ +:Version: $Revision: 1.20 $ .. contents:: @@ -85,7 +85,21 @@ Installation ============ Set aside 15-30 minutes. Please make sure you're using a supported version of -Python -- see `testing your python`_. +Python -- see `testing your python`_. There's three sections to this +installation guide: + +1. `basic installation steps`_ that all installers must follow +2. `shared environment steps`_ to take if you're installing on a shared + UNIX machine and want to restrict local access to roundup +3. `internet setup`_ steps to take if your tracker is to be used by the wider + internet community + +Most users will only need to follow the first step, since the environment will +be a trusted one. + + +Basic Installation Steps +~~~~~~~~~~~~~~~~~~~~~~~~ 1. To install the Roundup support code into your Python tree and Roundup scripts into /usr/local/bin:: @@ -139,32 +153,47 @@ Python -- see `testing your python`_. Once this is done, the instance has been created. -3. Each instance ideally should have its own UNIX group, so create - a UNIX group (edit ``/etc/group`` or your appropriate NIS map if - you're using NIS). To continue with my examples so far, I would - create the UNIX group 'support', although the name of the UNIX - group does not have to be the same as the instance name. To this - 'support' group I then add all of the UNIX usernames who will be - working with this Roundup instance. In addition to 'real' users, - the Roundup email gateway will need to have permissions to this - area as well, so add the user your mail service runs as to the - group. The UNIX group might then look like:: +3. XXX Set up the CGI interface + +4. XXX Set up the mail gateway + - support:*:1002:jblaine,samh,geezer,mail +Shared Environment Steps +~~~~~~~~~~~~~~~~~~~~~~~~ - If you intend to use the web interface (as most people do), you - should also add the username your web server runs as to the group. - My group now looks like this:: +Each instance ideally should have its own UNIX group, so create +a UNIX group (edit ``/etc/group`` or your appropriate NIS map if +you're using NIS). To continue with my examples so far, I would +create the UNIX group 'support', although the name of the UNIX +group does not have to be the same as the instance name. To this +'support' group I then add all of the UNIX usernames who will be +working with this Roundup instance. In addition to 'real' users, +the Roundup email gateway will need to have permissions to this +area as well, so add the user your mail service runs as to the +group. The UNIX group might then look like:: - support:*:1002:jblaine,samh,geezer,mail,apache + support:*:1002:jblaine,samh,geezer,mail -4. Configure your new instance by editing the file ``instance_config.py`` - located in the instance home you specified in step 2c above. This - file is Python code and must adhere to Python syntax rules, but - don't be daunted if you do not know Python - it should look pretty - straightfoward if you carefully read the comments in the file. +If you intend to use the web interface (as most people do), you +should also add the username your web server runs as to the group. +My group now looks like this:: -5. There are two supported ways to get emailed issues into the + support:*:1002:jblaine,samh,geezer,mail,apache + +An alternative to the above is to create a new user who has the sole +responsibility of running roundup. This user: + +1. runs the CGI interface daemon +2. runs regular polls for email +3. runs regular checks (using cron) to ensure the daemon is up +4. optionally has no login password so that nobody but the "root" user + may actually login and play with the roundup setup. + + +Internet Setup +~~~~~~~~~~~~~~ + +1. There are two supported ways to get emailed issues into the Roundup instance. You should pick ONE of the following, both of which will continue my example setup from above: @@ -185,11 +214,14 @@ Python -- see `testing your python`_. If you don't want to use the email component of Roundup, then remove the "``nosyreator.py``" module from your instance "``detectors``" directory. -6. Test the email gateway. Under most flavors of UNIX, this +2. Test the email gateway. Under most flavors of UNIX, this can be done by:: echo test | mail -s '[issue] test' support@YOUR_DOMAIN_HERE +XXX mention HTTPS +XXX mention Basic vs. cookie auth + Upgrading ========= diff --git a/roundup/backends/back_anydbm.py b/roundup/backends/back_anydbm.py index 4cdc41d..b9e33a1 100644 --- a/roundup/backends/back_anydbm.py +++ b/roundup/backends/back_anydbm.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_anydbm.py,v 1.71 2002-09-04 07:12:19 richard Exp $ +#$Id: back_anydbm.py,v 1.72 2002-09-05 00:33:22 richard Exp $ ''' This module defines a backend that saves the hyperdatabase in a database chosen by anydbm. It is guaranteed to always be available in python @@ -803,7 +803,7 @@ class Class(hyperdb.Class): l = [] for entry in value: if type(entry) != type(''): - raise ValueError, '"%s" multilink value (%r) ' + raise ValueError, '"%s" multilink value (%r) '\ 'must contain Strings'%(key, value) # if it isn't a number, it's a key if not num_re.match(entry): @@ -1909,6 +1909,9 @@ class IssueClass(Class, roundupdb.IssueClass): # #$Log: not supported by cvs2svn $ +#Revision 1.71 2002/09/04 07:12:19 richard +#better error message +# #Revision 1.70 2002/09/04 04:29:36 richard #bugfix # diff --git a/roundup/backends/back_gadfly.py b/roundup/backends/back_gadfly.py index c5d5133..ad156d2 100644 --- a/roundup/backends/back_gadfly.py +++ b/roundup/backends/back_gadfly.py @@ -1,4 +1,4 @@ -# $Id: back_gadfly.py,v 1.13 2002-09-04 07:12:19 richard Exp $ +# $Id: back_gadfly.py,v 1.14 2002-09-05 00:33:22 richard Exp $ __doc__ = ''' About Gadfly ============ @@ -923,7 +923,7 @@ class Class(hyperdb.Class): l = [] for entry in value: if type(entry) != type(''): - raise ValueError, '"%s" multilink value (%r) ' + raise ValueError, '"%s" multilink value (%r) '\ 'must contain Strings'%(key, value) # if it isn't a number, it's a key if not num_re.match(entry): @@ -1758,6 +1758,9 @@ class IssueClass(Class, roundupdb.IssueClass): # # $Log: not supported by cvs2svn $ +# Revision 1.13 2002/09/04 07:12:19 richard +# better error message +# # Revision 1.12 2002/09/04 04:30:18 richard # bugfix # diff --git a/PageTemplates/.cvsignore b/roundup/cgi/PageTemplates/.cvsignore similarity index 100% rename from PageTemplates/.cvsignore rename to roundup/cgi/PageTemplates/.cvsignore diff --git a/roundup/cgi/PageTemplates/ComputedAttribute.py b/roundup/cgi/PageTemplates/ComputedAttribute.py new file mode 100644 index 0000000..7117fb4 --- /dev/null +++ b/roundup/cgi/PageTemplates/ComputedAttribute.py @@ -0,0 +1,11 @@ +class ComputedAttribute: + def __init__(self, callable, level): + self.callable = callable + self.level = level + def __of__(self, *args): + if self.level > 0: + return self.callable + if isinstance(self.callable, type('')): + return getattr(args[0], self.callable) + return self.callable(*args) + diff --git a/PageTemplates/Expressions.py b/roundup/cgi/PageTemplates/Expressions.py similarity index 67% rename from PageTemplates/Expressions.py rename to roundup/cgi/PageTemplates/Expressions.py index b2adad2..105da31 100644 --- a/PageTemplates/Expressions.py +++ b/roundup/cgi/PageTemplates/Expressions.py @@ -23,8 +23,6 @@ import re, sys from TALES import Engine, CompilerError, _valid_name, NAME_RE, \ Undefined, Default, _parse_expr from string import strip, split, join, replace, lstrip -from Acquisition import aq_base, aq_inner, aq_parent - _engine = None def getEngine(): @@ -45,39 +43,23 @@ def installHandlers(engine): reg('not', NotExpr) reg('defer', DeferExpr) -if sys.modules.has_key('Zope'): - import AccessControl - from AccessControl import getSecurityManager - try: - from AccessControl import Unauthorized - except ImportError: - Unauthorized = "Unauthorized" - if hasattr(AccessControl, 'full_read_guard'): - from ZRPythonExpr import PythonExpr, _SecureModuleImporter, \ - call_with_ns +from PythonExpr import getSecurityManager, PythonExpr +try: + from zExceptions import Unauthorized +except ImportError: + Unauthorized = "Unauthorized" +def call_with_ns(f, ns, arg=1): + if arg==2: + return f(None, ns) else: - from ZPythonExpr import PythonExpr, _SecureModuleImporter, \ - call_with_ns -else: - from PythonExpr import getSecurityManager, PythonExpr - try: - from zExceptions import Unauthorized - except ImportError: - Unauthorized = "Unauthorized" - def call_with_ns(f, ns, arg=1): - if arg==2: - return f(None, ns) - else: - return f(ns) + return f(ns) - class _SecureModuleImporter: - """Simple version of the importer for use with trusted code.""" - __allow_access_to_unprotected_subobjects__ = 1 - def __getitem__(self, module): - __import__(module) - return sys.modules[module] - -SecureModuleImporter = _SecureModuleImporter() +class _SecureModuleImporter: + """Simple version of the importer for use with trusted code.""" + __allow_access_to_unprotected_subobjects__ = 1 + def __getitem__(self, module): + __import__(module) + return sys.modules[module] Undefs = (Undefined, AttributeError, KeyError, TypeError, IndexError, Unauthorized) @@ -90,7 +72,7 @@ def render(ob, ns): if hasattr(ob, '__render_with_namespace__'): ob = call_with_ns(ob.__render_with_namespace__, ns) else: - base = aq_base(ob) + base = ob if callable(base): try: if getattr(base, 'isDocTemp', 0): @@ -283,12 +265,9 @@ def restrictedTraverse(self, path, securityManager, if not path[0]: # If the path starts with an empty string, go to the root first. self = self.getPhysicalRoot() - if not securityManager.validateValue(self): - raise Unauthorized, name path.pop(0) - + path.reverse() - validate = securityManager.validate object = self #print 'TRAVERSE', (object, path) while path: @@ -303,73 +282,34 @@ def restrictedTraverse(self, path, securityManager, # Never allowed in a URL. raise AttributeError, name - if name=='..': - o = get(object, 'aq_parent', M) - if o is not M: - if not validate(object, object, name, o): - raise Unauthorized, name - object=o - continue - - t = get(object, '__bobo_traverse__', N) - if t is not N: - o=t(REQUEST, name) - - container = None - if has(o, 'im_self'): - container = o.im_self - elif (has(get(object, 'aq_base', object), name) - and get(object, name) == o): - container = object - if not validate(object, container, name, o): - raise Unauthorized, name - else: - # Try an attribute. - o = get(object, name, M) - # print '...', (object, name, M, o) - if o is not M: - # Check access to the attribute. - if has(object, 'aq_acquire'): - object.aq_acquire( - name, validate2, validate) - else: - if not validate(object, object, name, o): - raise Unauthorized, name - else: - # Try an item. - try: - # XXX maybe in Python 2.2 we can just check whether - # the object has the attribute "__getitem__" - # instead of blindly catching exceptions. - # print 'Try an item', (object, name) - o = object[name] - except AttributeError, exc: - if str(exc).find('__getitem__') >= 0: - # The object does not support the item interface. - # Try to re-raise the original attribute error. - # XXX I think this only happens with - # ExtensionClass instances. - get(object, name) - raise - except TypeError, exc: - if str(exc).find('unsubscriptable') >= 0: - # The object does not support the item interface. - # Try to re-raise the original attribute error. - # XXX This is sooooo ugly. - get(object, name) - raise - else: - # Check access to the item. - if not validate(object, object, name, o): - raise Unauthorized, name + # Try an attribute. + o = get(object, name, M) +# print '...', (object, name, M, o) + if o is M: + # Try an item. +# print '... try an item' + try: + # XXX maybe in Python 2.2 we can just check whether + # the object has the attribute "__getitem__" + # instead of blindly catching exceptions. + o = object[name] + except AttributeError, exc: + if str(exc).find('__getitem__') >= 0: + # The object does not support the item interface. + # Try to re-raise the original attribute error. + # XXX I think this only happens with + # ExtensionClass instances. + get(object, name) + raise + except TypeError, exc: + if str(exc).find('unsubscriptable') >= 0: + # The object does not support the item interface. + # Try to re-raise the original attribute error. + # XXX This is sooooo ugly. + get(object, name) + raise #print '... object is now', `o` object = o return object - -def validate2(orig, inst, name, v, real_validate): - if not real_validate(orig, inst, name, v): - raise Unauthorized, name - return 1 - diff --git a/roundup/cgi/PageTemplates/MultiMapping.py b/roundup/cgi/PageTemplates/MultiMapping.py new file mode 100644 index 0000000..b528288 --- /dev/null +++ b/roundup/cgi/PageTemplates/MultiMapping.py @@ -0,0 +1,25 @@ +import operator + +class MultiMapping: + def __init__(self, *stores): + self.stores = list(stores) + def __getitem__(self, key): + for store in self.stores: + if store.has_key(key): + return store[key] + raise KeyError, key + _marker = [] + def get(self, key, default=_marker): + for store in self.stores: + if store.has_key(key): + return store[key] + if default is self._marker: + raise KeyError, key + return default + def __len__(self): + return reduce(operator.add, [len(x) for x in stores], 0) + def push(self, store): + self.stores.append(store) + def pop(self): + return self.stores.pop() + diff --git a/PageTemplates/PageTemplate.py b/roundup/cgi/PageTemplates/PageTemplate.py similarity index 96% rename from PageTemplates/PageTemplate.py rename to roundup/cgi/PageTemplates/PageTemplate.py index d97b2a5..d30aa64 100755 --- a/PageTemplates/PageTemplate.py +++ b/roundup/cgi/PageTemplates/PageTemplate.py @@ -19,18 +19,16 @@ __version__='$Revision: 1.1 $'[11:-2] import sys -from TAL.TALParser import TALParser -from TAL.HTMLTALParser import HTMLTALParser -from TAL.TALGenerator import TALGenerator -from TAL.TALInterpreter import TALInterpreter +from roundup.cgi.TAL.TALParser import TALParser +from roundup.cgi.TAL.HTMLTALParser import HTMLTALParser +from roundup.cgi.TAL.TALGenerator import TALGenerator +from roundup.cgi.TAL.TALInterpreter import TALInterpreter from Expressions import getEngine from string import join, strip, rstrip, split, replace, lower, find from cStringIO import StringIO -from ExtensionClass import Base from ComputedAttribute import ComputedAttribute - -class PageTemplate(Base): +class PageTemplate: "Page Templates using TAL, TALES, and METAL" content_type = 'text/html' diff --git a/PageTemplates/PathIterator.py b/roundup/cgi/PageTemplates/PathIterator.py similarity index 100% rename from PageTemplates/PathIterator.py rename to roundup/cgi/PageTemplates/PathIterator.py diff --git a/PageTemplates/PythonExpr.py b/roundup/cgi/PageTemplates/PythonExpr.py similarity index 100% rename from PageTemplates/PythonExpr.py rename to roundup/cgi/PageTemplates/PythonExpr.py diff --git a/PageTemplates/README.txt b/roundup/cgi/PageTemplates/README.txt similarity index 100% rename from PageTemplates/README.txt rename to roundup/cgi/PageTemplates/README.txt diff --git a/PageTemplates/TALES.py b/roundup/cgi/PageTemplates/TALES.py similarity index 99% rename from PageTemplates/TALES.py rename to roundup/cgi/PageTemplates/TALES.py index 089ccbc..33b6e9f 100644 --- a/PageTemplates/TALES.py +++ b/roundup/cgi/PageTemplates/TALES.py @@ -17,7 +17,8 @@ An implementation of a generic TALES engine __version__='$Revision: 1.1 $'[11:-2] -import re, sys, ZTUtils +import re, sys +from roundup.cgi import ZTUtils from MultiMapping import MultiMapping StringType = type('') diff --git a/PageTemplates/__init__.py b/roundup/cgi/PageTemplates/__init__.py similarity index 94% rename from PageTemplates/__init__.py rename to roundup/cgi/PageTemplates/__init__.py index e1997a6..3d58de0 100644 --- a/PageTemplates/__init__.py +++ b/roundup/cgi/PageTemplates/__init__.py @@ -15,7 +15,7 @@ __doc__='''Package wrapper for Page Templates This wrapper allows the Page Template modules to be segregated in a separate package. -$Id: __init__.py,v 1.1 2002-08-30 08:27:34 richard Exp $''' +$Id: __init__.py,v 1.1 2002-09-05 00:37:09 richard Exp $''' __version__='$$'[11:-2] diff --git a/TAL/.cvsignore b/roundup/cgi/TAL/.cvsignore similarity index 100% rename from TAL/.cvsignore rename to roundup/cgi/TAL/.cvsignore diff --git a/TAL/HTMLParser.py b/roundup/cgi/TAL/HTMLParser.py similarity index 100% rename from TAL/HTMLParser.py rename to roundup/cgi/TAL/HTMLParser.py diff --git a/TAL/HTMLTALParser.py b/roundup/cgi/TAL/HTMLTALParser.py similarity index 100% rename from TAL/HTMLTALParser.py rename to roundup/cgi/TAL/HTMLTALParser.py diff --git a/TAL/README.txt b/roundup/cgi/TAL/README.txt similarity index 100% rename from TAL/README.txt rename to roundup/cgi/TAL/README.txt diff --git a/TAL/TALDefs.py b/roundup/cgi/TAL/TALDefs.py similarity index 100% rename from TAL/TALDefs.py rename to roundup/cgi/TAL/TALDefs.py diff --git a/TAL/TALGenerator.py b/roundup/cgi/TAL/TALGenerator.py similarity index 100% rename from TAL/TALGenerator.py rename to roundup/cgi/TAL/TALGenerator.py diff --git a/TAL/TALInterpreter.py b/roundup/cgi/TAL/TALInterpreter.py similarity index 100% rename from TAL/TALInterpreter.py rename to roundup/cgi/TAL/TALInterpreter.py diff --git a/TAL/TALParser.py b/roundup/cgi/TAL/TALParser.py similarity index 100% rename from TAL/TALParser.py rename to roundup/cgi/TAL/TALParser.py diff --git a/TAL/XMLParser.py b/roundup/cgi/TAL/XMLParser.py similarity index 91% rename from TAL/XMLParser.py rename to roundup/cgi/TAL/XMLParser.py index 71a65ab..98cc4d3 100644 --- a/TAL/XMLParser.py +++ b/roundup/cgi/TAL/XMLParser.py @@ -15,8 +15,6 @@ Generic expat-based XML parser base class. """ -import zLOG - class XMLParser: ordered_attributes = 0 @@ -50,8 +48,8 @@ class XMLParser: try: self.parser.ordered_attributes = self.ordered_attributes except AttributeError: - zLOG.LOG("TAL.XMLParser", zLOG.INFO, - "Can't set ordered_attributes") + #zLOG.LOG("TAL.XMLParser", zLOG.INFO, + # "Can't set ordered_attributes") self.ordered_attributes = 0 for name in self.handler_names: method = getattr(self, name, None) @@ -59,8 +57,9 @@ class XMLParser: try: setattr(p, name, method) except AttributeError: - zLOG.LOG("TAL.XMLParser", zLOG.PROBLEM, - "Can't set expat handler %s" % name) + #zLOG.LOG("TAL.XMLParser", zLOG.PROBLEM, + # "Can't set expat handler %s" % name) + pass def createParser(self, encoding=None): global XMLParseError diff --git a/TAL/__init__.py b/roundup/cgi/TAL/__init__.py similarity index 100% rename from TAL/__init__.py rename to roundup/cgi/TAL/__init__.py diff --git a/TAL/markupbase.py b/roundup/cgi/TAL/markupbase.py similarity index 100% rename from TAL/markupbase.py rename to roundup/cgi/TAL/markupbase.py diff --git a/ZTUtils/.cvsignore b/roundup/cgi/ZTUtils/.cvsignore similarity index 100% rename from ZTUtils/.cvsignore rename to roundup/cgi/ZTUtils/.cvsignore diff --git a/ZTUtils/Batch.py b/roundup/cgi/ZTUtils/Batch.py similarity index 95% rename from ZTUtils/Batch.py rename to roundup/cgi/ZTUtils/Batch.py index 88494f8..713d771 100644 --- a/ZTUtils/Batch.py +++ b/roundup/cgi/ZTUtils/Batch.py @@ -12,18 +12,16 @@ ############################################################################## __doc__='''Batch class, for iterating over a sequence in batches -$Id: Batch.py,v 1.1 2002-08-30 08:25:33 richard Exp $''' +$Id: Batch.py,v 1.1 2002-09-05 00:37:09 richard Exp $''' __version__='$Revision: 1.1 $'[11:-2] -from ExtensionClass import Base - -class LazyPrevBatch(Base): +class LazyPrevBatch: def __of__(self, parent): return Batch(parent._sequence, parent._size, parent.first - parent._size + parent.overlap, 0, parent.orphan, parent.overlap) -class LazyNextBatch(Base): +class LazyNextBatch: def __of__(self, parent): try: parent._sequence[parent.end] except IndexError: return None @@ -31,12 +29,12 @@ class LazyNextBatch(Base): parent.end - parent.overlap, 0, parent.orphan, parent.overlap) -class LazySequenceLength(Base): +class LazySequenceLength: def __of__(self, parent): parent.sequence_length = l = len(parent._sequence) return l -class Batch(Base): +class Batch: """Create a sequence batch""" __allow_access_to_unprotected_subobjects__ = 1 diff --git a/ZTUtils/Iterator.py b/roundup/cgi/ZTUtils/Iterator.py similarity index 98% rename from ZTUtils/Iterator.py rename to roundup/cgi/ZTUtils/Iterator.py index cf3d51c..d13b5c2 100644 --- a/ZTUtils/Iterator.py +++ b/roundup/cgi/ZTUtils/Iterator.py @@ -18,7 +18,7 @@ The Iterator() function accepts either a sequence or a Python iterator. The next() method fetches the next item, and returns true if it succeeds. -$Id: Iterator.py,v 1.1 2002-08-30 08:25:34 richard Exp $''' +$Id: Iterator.py,v 1.1 2002-09-05 00:37:09 richard Exp $''' __version__='$Revision: 1.1 $'[11:-2] import string diff --git a/ZTUtils/__init__.py b/roundup/cgi/ZTUtils/__init__.py similarity index 64% rename from ZTUtils/__init__.py rename to roundup/cgi/ZTUtils/__init__.py index 133f817..f9eb32c 100644 --- a/ZTUtils/__init__.py +++ b/roundup/cgi/ZTUtils/__init__.py @@ -12,20 +12,9 @@ ############################################################################## __doc__='''Package of template utility classes and functions. -$Id: __init__.py,v 1.1 2002-08-30 08:25:34 richard Exp $''' +$Id: __init__.py,v 1.1 2002-09-05 00:37:09 richard Exp $''' __version__='$Revision: 1.1 $'[11:-2] from Batch import Batch from Iterator import Iterator -from Tree import TreeMaker, encodeExpansion, decodeExpansion, a2b, b2a -from SimpleTree import SimpleTreeMaker - -import sys -if sys.modules.has_key('Zope'): - del sys - __allow_access_to_unprotected_subobjects__ = 1 - __roles__ = None - - from Zope import Batch, TreeMaker, SimpleTreeMaker, LazyFilter - from Zope import url_query, make_query, make_hidden_input diff --git a/roundup/cgi/templating.py b/roundup/cgi/templating.py index aea8651..d7afb83 100644 --- a/roundup/cgi/templating.py +++ b/roundup/cgi/templating.py @@ -16,31 +16,11 @@ try: except ImportError: StructuredText = None -# Make sure these modules are loaded -# I need these to run PageTemplates outside of Zope :( -# If we're running in a Zope environment, these modules will be loaded -# already... -if not sys.modules.has_key('zLOG'): - import zLOG - sys.modules['zLOG'] = zLOG -if not sys.modules.has_key('MultiMapping'): - import MultiMapping - sys.modules['MultiMapping'] = MultiMapping -if not sys.modules.has_key('ComputedAttribute'): - import ComputedAttribute - sys.modules['ComputedAttribute'] = ComputedAttribute -if not sys.modules.has_key('ExtensionClass'): - import ExtensionClass - sys.modules['ExtensionClass'] = ExtensionClass -if not sys.modules.has_key('Acquisition'): - import Acquisition - sys.modules['Acquisition'] = Acquisition - -# now it's safe to import PageTemplates, TAL and ZTUtils -from PageTemplates import PageTemplate -from PageTemplates.Expressions import getEngine -from TAL.TALInterpreter import TALInterpreter -import ZTUtils +# bring in the templating support +from roundup.cgi.PageTemplates import PageTemplate +from roundup.cgi.PageTemplates.Expressions import getEngine +from roundup.cgi.TAL.TALInterpreter import TALInterpreter +from roundup.cgi import ZTUtils # XXX WAH pagetemplates aren't pickleable :( #def getTemplate(dir, name, classname=None, request=None): -- 2.30.2