Code

cleanup
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 15 Aug 2002 00:40:10 +0000 (00:40 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 15 Aug 2002 00:40:10 +0000 (00:40 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@952 57a73879-2fb5-44c3-a270-3262357dd7e2

roundup/cgi_client.py
roundup/htmltemplate.py
roundup/template_funcs.py

index 4ff818f40712cfb23dea8b87f27993727c559604..b1ce70cf7fd31ca4112a71a8c5fce6cc8779ee8a 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: cgi_client.py,v 1.157 2002-08-13 20:16:09 gmcm Exp $
+# $Id: cgi_client.py,v 1.158 2002-08-15 00:40:10 richard Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -1113,7 +1113,9 @@ function help_window(helpurl, width, height) {
 
     def showuser(self, message=None, num_re=re.compile('^\d+$')):
         '''Display a user page for editing. Make sure the user is allowed
-            to edit this node, and also check for password changes.
+           to edit this node, and also check for password changes.
+
+           Note: permission checks for this node are handled in the template.
         '''
         user = self.db.user
 
@@ -1123,11 +1125,6 @@ function help_window(helpurl, width, height) {
         except IndexError:
             raise NotFound, 'user%s'%self.nodeid
 
-        # ok, so we need to be able to edit everything, or be this node's
-        # user
-        userid = self.db.user.lookup(self.user)
-        # removed check on user's permissions - this needs to be done
-       # through require tags in user.item
         #
         # perform any editing
         #
@@ -1748,6 +1745,15 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.157  2002/08/13 20:16:09  gmcm
+# Use a real parser for templates.
+# Rewrite htmltemplate to use the parser (hack, hack).
+# Move the "do_XXX" methods to template_funcs.py.
+# Redo the funcion tests (but not Template tests - they're hopeless).
+# Simplified query form in cgi_client.
+# Ability to delete msgs, files, queries.
+# Ability to edit the metadata on files.
+#
 # Revision 1.156  2002/08/01 15:06:06  gmcm
 # Use same regex to split search terms as used to index text.
 # Fix to back_metakit for not changing journaltag on reopen.
index 68c4b4b558ea8700ecf42243ccf94b0923522cda..d1fd2523307e6cd8f96ce08e226a020e34ba1520 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: htmltemplate.py,v 1.110 2002-08-13 20:16:09 gmcm Exp $
+# $Id: htmltemplate.py,v 1.111 2002-08-15 00:40:10 richard Exp $
 
 __doc__ = """
 Template engine.
@@ -81,7 +81,7 @@ def _test(attributes, client, classname, nodeid):
     if nodeid is None:
         return 0
     if not tests:
-       return 0
+        return 0
     for propname, value in tests.items():
         if value == '$userid':
             tests[propname] = userid
@@ -108,7 +108,7 @@ def _exists(attributes, cl, props, nodeid):
     if nodeid:
         return cl.get(nodeid, nm)
     return props.get(nm, 0)
-    
+
 class Template:
     ''' base class of all templates.
 
@@ -120,7 +120,7 @@ class Template:
         else:
             self.client = weakref.proxy(client)
         self.templatedir = templates
-        self.compiledtemplatedir = self.templatedir+'c'
+        self.compiledtemplatedir = self.templatedir + 'c'
         self.classname = classname
         self.cl = self.client.db.getclass(self.classname)
         self.properties = self.cl.getprops()
@@ -128,16 +128,33 @@ class Template:
         self.filterspec = None
         self.columns = None
         self.nodeid = None
+
     def _load(self):
+        ''' Load a template from disk and parse it.
+
+            Once parsed, the template is stored as a pickle in the
+            "htmlc" directory of the instance. If the file in there is
+            newer than the source template file, it's used in preference so
+            we don't have to re-parse.
+        '''
+        # figure where the template source is
         src = os.path.join(self.templatedir, self.classname + self.extension)
+
         if not os.path.exists(src):
+            # hrm, nothing exactly matching what we're after, see if we can
+            # fall back on another template
             if hasattr(self, 'fallbackextension'):
                 self.extension = self.fallbackextension
                 return self._load()
             raise MissingTemplateError, self.classname + self.extension
-        cpl = os.path.join(self.compiledtemplatedir, self.classname + self.extension)
-        if ( not os.path.exists(cpl)
-             or os.stat(cpl)[MTIME] < os.stat(src)[MTIME] ):
+
+        # figure where the compiled template should be
+        cpl = os.path.join(self.compiledtemplatedir,
+            self.classname + self.extension)
+
+        if (not os.path.exists(cpl)
+             or os.stat(cpl)[MTIME] < os.stat(src)[MTIME]):
+            # there's either no compiled template, or it's out of date
             parser = RoundupTemplate()
             parser.feed(open(src, 'r').read())
             tmplt = parser.structure
@@ -151,26 +168,46 @@ class Template:
                 print "ouch in pickling: got a %s %r" % (e, e.args)
                 pass
         else:
+            # load the compiled template
             f = open(cpl, 'rb')
             tmplt = pickle.load(f)
         return tmplt
+
     def _render(self, tmplt=None, test=_test, display=_display, exists=_exists):
+        ''' Render the template
+        '''
         if tmplt is None:
             tmplt = self.template
+
+        # go through the list of template "commands"
         for entry in tmplt:
             if isinstance(entry, type('')):
+                # string - just write it out
                 self.client.write(entry)
+
             elif isinstance(entry, Require):
-                if test(entry.attributes, self.client, self.classname, self.nodeid):
+                # a <require> tag
+                if test(entry.attributes, self.client, self.classname,
+                        self.nodeid):
+                    # require test passed, render the ok clause
                     self._render(entry.ok)
                 elif entry.fail:
+                    # if there's a fail clause, render it
                     self._render(entry.fail)
+
             elif isinstance(entry, Display):
-                display(entry.attributes, self.client, self.classname, self.cl, self.properties, self.nodeid, self.filterspec)
+                # execute the <display> function
+                display(entry.attributes, self.client, self.classname,
+                    self.cl, self.properties, self.nodeid, self.filterspec)
+
             elif isinstance(entry, Property):
-                if self.columns is None:        # doing an Item
-                    if exists(entry.attributes, self.cl, self.properties, self.nodeid):
+                # do a <property> test
+                if self.columns is None:
+                    # doing an Item - see if the property is present
+                    if exists(entry.attributes, self.cl, self.properties,
+                            self.nodeid):
                         self._render(entry.ok)
+                # XXX erm, should this be commented out?
                 #elif entry.attributes[0][1] in self.columns:
                 else:
                     self._render(entry.ok)
@@ -183,163 +220,177 @@ class IndexTemplate(Template):
         has group by lines
         has full text search match lines '''
     extension = '.index'
+
     def __init__(self, client, templates, classname):
         Template.__init__(self, client, templates, classname)
-    def render(self, filterspec={}, search_text='', filter=[], columns=[], 
+
+    def render(self, **kw):
+        ''' Render the template - well, wrap the rendering in a try/finally
+            so we're guaranteed to clean up after ourselves
+        '''
+        try:
+            self.renderInner(**kw)
+        finally:
+            self.cl = self.properties = self.client = None
+        
+    def renderInner(self, filterspec={}, search_text='', filter=[], columns=[], 
             sort=[], group=[], show_display_form=1, nodeids=None,
             show_customization=1, show_nodes=1, pagesize=50, startwith=0,
             simple_search=1, xtracols=None):
+        ''' Take all the index arguments and render some HTML
+        '''
 
-        try:
-            self.filterspec = filterspec        
-            w = self.client.write
-            cl = self.cl
-            properties = self.properties
-            if xtracols is None:
-                xtracols = []
-            
-            # XXX deviate from spec here ...
-            # load the index section template and figure the default columns from it
-            displayable_props = []
-            all_columns = []
-            for node in self.template:
-                if isinstance(node, Property):
-                    colnm = node.attributes[0][1]
-                    if properties.has_key(colnm):
-                        displayable_props.append(colnm)
-                        all_columns.append(colnm)
-                    elif colnm in xtracols:
-                        all_columns.append(colnm)
-            if not columns:
-                columns = all_columns
-            else:
-                # re-sort columns to be the same order as displayable_props
-                l = []
-                for name in all_columns:
-                    if name in columns:
-                        l.append(name)
-                columns = l
-            self.columns = columns
+        self.filterspec = filterspec        
+        w = self.client.write
+        cl = self.cl
+        properties = self.properties
+        if xtracols is None:
+            xtracols = []
 
-            # optimize the template
-            self.template = self._optimize(self.template)
-            
-            # display the filter section
-            if (show_display_form and 
-                    self.client.instance.FILTER_POSITION in ('top and bottom', 'top')):
-                w('<form onSubmit="return submit_once()" action="%s">\n'%self.client.classname)
-                self.filter_section(search_text, filter, columns, group,
-                    displayable_props, sort, filterspec, pagesize, startwith, simple_search)
+        # XXX deviate from spec here ...
+        # load the index section template and figure the default columns from it
+        displayable_props = []
+        all_columns = []
+        for node in self.template:
+            if isinstance(node, Property):
+                colnm = node.attributes[0][1]
+                if properties.has_key(colnm):
+                    displayable_props.append(colnm)
+                    all_columns.append(colnm)
+                elif colnm in xtracols:
+                    all_columns.append(colnm)
+        if not columns:
+            columns = all_columns
+        else:
+            # re-sort columns to be the same order as displayable_props
+            l = []
+            for name in all_columns:
+                if name in columns:
+                    l.append(name)
+            columns = l
+        self.columns = columns
 
-            # now display the index section
-            w('<table width=100% border=0 cellspacing=0 cellpadding=2>\n')
-            w('<tr class="list-header">\n')
-            for name in columns:
-                cname = name.capitalize()
-                if show_display_form and not cname in xtracols:
-                    sb = self.sortby(name, search_text, filterspec, columns, filter, 
-                            group, sort, pagesize)
-                    anchor = "%s?%s"%(self.client.classname, sb)
-                    w('<td><span class="list-header"><a href="%s">%s</a>'
-                        '</span></td>\n'%(anchor, cname))
-                else:
-                    w('<td><span class="list-header">%s</span></td>\n'%cname)
-            w('</tr>\n')
+        # optimize the template
+        self.template = self._optimize(self.template)
+        
+        # display the filter section
+        if (show_display_form and
+                self.client.instance.FILTER_POSITION.startswith('top')):
+            w('<form onSubmit="return submit_once()" action="%s">\n'%
+                self.client.classname)
+            self.filter_section(search_text, filter, columns, group,
+                displayable_props, sort, filterspec, pagesize, startwith,
+                simple_search)
+
+        # now display the index section
+        w('<table width=100% border=0 cellspacing=0 cellpadding=2>\n')
+        w('<tr class="list-header">\n')
+        for name in columns:
+            cname = name.capitalize()
+            if show_display_form and not cname in xtracols:
+                sb = self.sortby(name, search_text, filterspec, columns, filter, 
+                        group, sort, pagesize)
+                anchor = "%s?%s"%(self.client.classname, sb)
+                w('<td><span class="list-header"><a href="%s">%s</a>'
+                    '</span></td>\n'%(anchor, cname))
+            else:
+                w('<td><span class="list-header">%s</span></td>\n'%cname)
+        w('</tr>\n')
 
-            # this stuff is used for group headings - optimise the group names
-            old_group = None
-            group_names = []
-            if group:
-                for name in group:
-                    if name[0] == '-': group_names.append(name[1:])
-                    else: group_names.append(name)
+        # this stuff is used for group headings - optimise the group names
+        old_group = None
+        group_names = []
+        if group:
+            for name in group:
+                if name[0] == '-': group_names.append(name[1:])
+                else: group_names.append(name)
 
-            # now actually loop through all the nodes we get from the filter and
-            # apply the template
-            if show_nodes:
-                matches = None
-                if nodeids is None:
-                    if search_text != '':
-                        matches = self.client.db.indexer.search(
-                            re.findall(r'\b\w{2,25}\b', search_text), cl)
-                    nodeids = cl.filter(matches, filterspec, sort, group)
-                linecount = 0
-                for nodeid in nodeids[startwith:startwith+pagesize]:
-                    # check for a group heading
-                    if group_names:
-                        this_group = [cl.get(nodeid, name, _('[no value]'))
-                            for name in group_names]
-                        if this_group != old_group:
-                            l = []
-                            for name in group_names:
-                                prop = properties[name]
-                                if isinstance(prop, hyperdb.Link):
-                                    group_cl = self.client.db.getclass(prop.classname)
-                                    key = group_cl.getkey()
-                                    if key is None:
-                                        key = group_cl.labelprop()
-                                    value = cl.get(nodeid, name)
-                                    if value is None:
-                                        l.append(_('[unselected %(classname)s]')%{
-                                            'classname': prop.classname})
-                                    else:
-                                        l.append(group_cl.get(value, key))
-                                elif isinstance(prop, hyperdb.Multilink):
-                                    group_cl = self.client.db.getclass(prop.classname)
-                                    key = group_cl.getkey()
-                                    for value in cl.get(nodeid, name):
-                                        l.append(group_cl.get(value, key))
+        # now actually loop through all the nodes we get from the filter and
+        # apply the template
+        if show_nodes:
+            matches = None
+            if nodeids is None:
+                if search_text != '':
+                    matches = self.client.db.indexer.search(
+                        re.findall(r'\b\w{2,25}\b', search_text), cl)
+                nodeids = cl.filter(matches, filterspec, sort, group)
+            linecount = 0
+            for nodeid in nodeids[startwith:startwith+pagesize]:
+                # check for a group heading
+                if group_names:
+                    this_group = [cl.get(nodeid, name, _('[no value]'))
+                        for name in group_names]
+                    if this_group != old_group:
+                        l = []
+                        for name in group_names:
+                            prop = properties[name]
+                            if isinstance(prop, hyperdb.Link):
+                                group_cl = self.client.db.getclass(prop.classname)
+                                key = group_cl.getkey()
+                                if key is None:
+                                    key = group_cl.labelprop()
+                                value = cl.get(nodeid, name)
+                                if value is None:
+                                    l.append(_('[unselected %(classname)s]')%{
+                                        'classname': prop.classname})
                                 else:
-                                    value = cl.get(nodeid, name, 
-                                        _('[no value]'))
-                                    if value is None:
-                                        value = _('[empty %(name)s]')%locals()
-                                    else:
-                                        value = str(value)
-                                    l.append(value)
-                            w('<tr class="section-bar">'
-                            '<td align=middle colspan=%s>'
-                            '<strong>%s</strong></td></tr>\n'%(
-                                len(columns), ', '.join(l)))
-                            old_group = this_group
+                                    l.append(group_cl.get(value, key))
+                            elif isinstance(prop, hyperdb.Multilink):
+                                group_cl = self.client.db.getclass(prop.classname)
+                                key = group_cl.getkey()
+                                for value in cl.get(nodeid, name):
+                                    l.append(group_cl.get(value, key))
+                            else:
+                                value = cl.get(nodeid, name, 
+                                    _('[no value]'))
+                                if value is None:
+                                    value = _('[empty %(name)s]')%locals()
+                                else:
+                                    value = str(value)
+                                l.append(value)
+                        w('<tr class="section-bar">'
+                        '<td align=middle colspan=%s>'
+                        '<strong>%s</strong></td></tr>\n'%(
+                            len(columns), ', '.join(l)))
+                        old_group = this_group
 
-                    # display this node's row
-                    self.nodeid = nodeid 
-                    self._render()
-                    if matches:
-                        self.node_matches(matches[nodeid], len(columns))
-                    self.nodeid = None
+                # display this node's row
+                self.nodeid = nodeid 
+                self._render()
+                if matches:
+                    self.node_matches(matches[nodeid], len(columns))
+                self.nodeid = None
 
-            w('</table>\n')
-            # the previous and next links
-            if nodeids:
-                baseurl = self.buildurl(filterspec, search_text, filter,
-                    columns, sort, group, pagesize)
-                if startwith > 0:
-                    prevurl = '<a href="%s&:startwith=%s">&lt;&lt; '\
-                        'Previous page</a>'%(baseurl, max(0, startwith-pagesize)) 
-                else:
-                    prevurl = "" 
-                if startwith + pagesize < len(nodeids):
-                    nexturl = '<a href="%s&:startwith=%s">Next page '\
-                        '&gt;&gt;</a>'%(baseurl, startwith+pagesize)
-                else:
-                    nexturl = ""
-                if prevurl or nexturl:
-                    w('''<table width="100%%"><tr>
-                          <td width="50%%" align="center">%s</td>
-                          <td width="50%%" align="center">%s</td>
-                         </tr></table>\n'''%(prevurl, nexturl))
+        w('</table>\n')
+        # the previous and next links
+        if nodeids:
+            baseurl = self.buildurl(filterspec, search_text, filter,
+                columns, sort, group, pagesize)
+            if startwith > 0:
+                prevurl = '<a href="%s&:startwith=%s">&lt;&lt; '\
+                    'Previous page</a>'%(baseurl, max(0, startwith-pagesize)) 
+            else:
+                prevurl = "" 
+            if startwith + pagesize < len(nodeids):
+                nexturl = '<a href="%s&:startwith=%s">Next page '\
+                    '&gt;&gt;</a>'%(baseurl, startwith+pagesize)
+            else:
+                nexturl = ""
+            if prevurl or nexturl:
+                w('''<table width="100%%"><tr>
+                      <td width="50%%" align="center">%s</td>
+                      <td width="50%%" align="center">%s</td>
+                     </tr></table>\n'''%(prevurl, nexturl))
 
-            # display the filter section
-            if (show_display_form and hasattr(self.client.instance, 'FILTER_POSITION') and
-                    self.client.instance.FILTER_POSITION in ('top and bottom', 'bottom')):
-                w('<form onSubmit="return submit_once()" action="%s">\n'%
-                    self.client.classname)
-                self.filter_section(search_text, filter, columns, group,
-                    displayable_props, sort, filterspec, pagesize, startwith, simple_search)
-        finally:
-            self.cl = self.properties = self.client = None
+        # display the filter section
+        if (show_display_form and hasattr(self.client.instance,
+                'FILTER_POSITION') and
+                self.client.instance.FILTER_POSITION.endswith('bottom')):
+            w('<form onSubmit="return submit_once()" action="%s">\n'%
+                self.client.classname)
+            self.filter_section(search_text, filter, columns, group,
+                displayable_props, sort, filterspec, pagesize, startwith,
+                simple_search)
 
     def _optimize(self, tmplt):
         columns = self.columns
@@ -352,8 +403,10 @@ class IndexTemplate(Template):
                 t.append(entry)
         return t
     
-    def buildurl(self, filterspec, search_text, filter, columns, sort, group, pagesize):
-        d = {'pagesize':pagesize, 'pagesize':pagesize, 'classname':self.classname}
+    def buildurl(self, filterspec, search_text, filter, columns, sort, group,
+            pagesize):
+        d = {'pagesize':pagesize, 'pagesize':pagesize,
+             'classname':self.classname}
         if search_text:
             d['searchtext'] = 'search_text=%s&' % search_text
         else:
@@ -367,8 +420,10 @@ class IndexTemplate(Template):
             vals = ','.join(map(urllib.quote,vals))
             tmp.append('%s=%s' % (col, vals))
         d['filters'] = '&'.join(tmp)
-        return ('%(classname)s?%(searchtext)s%(filters)s&:sort=%(sort)s&:filter=%(filter)s'
-                '&:group=%(group)s&:columns=%(columns)s&:pagesize=%(pagesize)s' % d )
+        return ('%(classname)s?%(searchtext)s%(filters)s&:sort=%(sort)s&'
+                ':filter=%(filter)s&:group=%(group)s&:columns=%(columns)s&'
+                ':pagesize=%(pagesize)s'%d)
+
     def node_matches(self, match, colspan):
         ''' display the files and messages for a node that matched a
             full text search
@@ -421,12 +476,12 @@ class IndexTemplate(Template):
         w(  '</tr>')
         # see if we have any indexed properties
         if self.client.classname in self.client.db.config.HEADER_SEARCH_LINKS:
-        #if self.properties.has_key('messages') or self.properties.has_key('files'):
-            w(  '<tr class="location-bar">')
-            w(  ' <td align="right" class="form-label"><b>Search Terms</b></td>')
-            w(  ' <td colspan=6 class="form-text">&nbsp;&nbsp;&nbsp;<input type="text"'
-                'name="search_text" value="%s" size="50"></td>' % search_text)
-            w(  '</tr>')
+            w('<tr class="location-bar">')
+            w(' <td align="right" class="form-label"><b>Search Terms</b></td>')
+            w(' <td colspan=6 class="form-text">&nbsp;&nbsp;&nbsp;'
+              '<input type="text"name="search_text" value="%s" size="50">'
+              '</td>'%search_text)
+            w('</tr>')
         w(  '<tr class="location-bar">')
         w(  ' <th align="center" width="20%">&nbsp;</th>')
         w(_(' <th align="center" width="10%">Show</th>'))
@@ -600,11 +655,11 @@ class IndexTemplate(Template):
             sort, filterspec, pagesize, startwith, simpleform=1):
         w = self.client.write
         if simpleform:
-            w(self.simple_filter_form(search_text, filter, columns, group, all_columns,
-                           sort, filterspec, pagesize))
+            w(self.simple_filter_form(search_text, filter, columns, group,
+                all_columns, sort, filterspec, pagesize))
         else:
             w(self.filter_form(search_text, filter, columns, group, all_columns,
-                           sort, filterspec, pagesize))
+                sort, filterspec, pagesize))
         w(' <tr class="location-bar">\n')
         w('  <td colspan=7><hr></td>\n')
         w(' </tr>\n')
@@ -631,8 +686,8 @@ class IndexTemplate(Template):
             w(' </tr>\n')
         w('</table>\n')
 
-    def sortby(self, sort_name, search_text, filterspec, columns, filter, group, sort,
-            pagesize):
+    def sortby(self, sort_name, search_text, filterspec, columns, filter,
+            group, sort, pagesize):
         ''' Figure the link for a column heading so we can sort by that
             column
         '''
@@ -690,8 +745,9 @@ class ItemTemplate(Template):
                 #  designators...
 
             w = self.client.write
-            w('<form onSubmit="return submit_once()" action="%s%s" method="POST" enctype="multipart/form-data">'%(
-                self.classname, nodeid))
+            w('<form onSubmit="return submit_once()" action="%s%s" '
+                'method="POST" enctype="multipart/form-data">'%(self.classname,
+                nodeid))
             try:
                 self._render()
             except:
@@ -704,7 +760,6 @@ class ItemTemplate(Template):
             w('</form>')
         finally:
             self.cl = self.properties = self.client = None
-        
 
 class NewItemTemplate(Template):
     ''' display a form for creating a new node '''
@@ -717,13 +772,15 @@ class NewItemTemplate(Template):
             self.form = form
             w = self.client.write
             c = self.client.classname
-            w('<form onSubmit="return submit_once()" action="new%s" method="POST" enctype="multipart/form-data">'%c)
+            w('<form onSubmit="return submit_once()" action="new%s" '
+                'method="POST" enctype="multipart/form-data">'%c)
             for key in form.keys():
                 if key[0] == ':':
                     value = form[key].value
                     if type(value) != type([]): value = [value]
                     for value in value:
-                        w('<input type="hidden" name="%s" value="%s">'%(key, value))
+                        w('<input type="hidden" name="%s" value="%s">'%(key,
+                            value))
             self._render()
             w('</form>')
         finally:
@@ -740,6 +797,15 @@ for nm in template_funcs.__dict__.keys():
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.110  2002/08/13 20:16:09  gmcm
+# Use a real parser for templates.
+# Rewrite htmltemplate to use the parser (hack, hack).
+# Move the "do_XXX" methods to template_funcs.py.
+# Redo the funcion tests (but not Template tests - they're hopeless).
+# Simplified query form in cgi_client.
+# Ability to delete msgs, files, queries.
+# Ability to edit the metadata on files.
+#
 # Revision 1.109  2002/08/01 15:06:08  gmcm
 # Use same regex to split search terms as used to index text.
 # Fix to back_metakit for not changing journaltag on reopen.
index b7cf387be5b728ad8cd0d0bf218369af088af920..2087472e9b478ad329fc308e7781b67c13398d53 100755 (executable)
@@ -1,10 +1,13 @@
+# 
+# $Id: template_funcs.py,v 1.2 2002-08-15 00:40:10 richard Exp $
+#
 import hyperdb, date, password
 from i18n import _
 import htmltemplate
 import cgi, os, StringIO, urllib, types
 
-
-def do_plain(client, classname, cl, props, nodeid, filterspec, property, escape=0, lookup=1):
+def do_plain(client, classname, cl, props, nodeid, filterspec, property,
+        escape=0, lookup=1):
     ''' display a String property directly;
 
         display a Date property in a specified time zone with an option to
@@ -52,11 +55,13 @@ def do_plain(client, classname, cl, props, nodeid, filterspec, property, escape=
         value = cgi.escape(value)
     return value
 
-def do_stext(client, classname, cl, props, nodeid, filterspec, property, escape=0):
+def do_stext(client, classname, cl, props, nodeid, filterspec, property,
+        escape=0):
     '''Render as structured text using the StructuredText module
        (see above for details)
     '''
-    s = do_plain(client, classname, cl, props, nodeid, filterspec, property, escape=escape)
+    s = do_plain(client, classname, cl, props, nodeid, filterspec, property,
+        escape=escape)
     if not StructuredText:
         return s
     return StructuredText(s,level=1,header=0)
@@ -95,7 +100,8 @@ def make_sort_function(client, filterspec, classname):
         return cmp(linkcl.get(a, sort_on), linkcl.get(b, sort_on))
     return sortfunc
 
-def do_field(client, classname, cl, props, nodeid, filterspec, property, size=None, showid=0):
+def do_field(client, classname, cl, props, nodeid, filterspec, property,
+        size=None, showid=0):
     ''' display a property like the plain displayer, but in a text field
         to be edited
 
@@ -123,12 +129,14 @@ def do_field(client, classname, cl, props, nodeid, filterspec, property, size=No
         s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
     elif isinstance(propclass, hyperdb.Boolean):
         checked = value and "checked" or ""
-        s = '<input type="radio" name="%s" value="yes" %s>Yes'%(property, checked)
+        s = '<input type="radio" name="%s" value="yes" %s>Yes'%(property,
+            checked)
         if checked:
             checked = ""
         else:
             checked = "checked"
-        s += '<input type="radio" name="%s" value="no" %s>No'%(property, checked)
+        s += '<input type="radio" name="%s" value="no" %s>No'%(property,
+            checked)
     elif isinstance(propclass, hyperdb.Number):
         s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
     elif isinstance(propclass, hyperdb.Password):
@@ -178,7 +186,8 @@ def do_field(client, classname, cl, props, nodeid, filterspec, property, size=No
         s = _('Plain: bad propclass "%(propclass)s"')%locals()
     return s
 
-def do_multiline(client, classname, cl, props, nodeid, filterspec, property, rows=5, cols=40):
+def do_multiline(client, classname, cl, props, nodeid, filterspec, property,
+        rows=5, cols=40):
     ''' display a string property in a multiline text edit field
     '''
     if not nodeid and client.form is None and filterspec is None:
@@ -199,8 +208,8 @@ def do_multiline(client, classname, cl, props, nodeid, filterspec, property, row
     return '<textarea name="%s" rows="%s" cols="%s">%s</textarea>'%(
         property, rows, cols, value)
 
-def do_menu(client, classname, cl, props, nodeid, filterspec, property, size=None, height=None, showid=0,
-        additional=[], **conditions):
+def do_menu(client, classname, cl, props, nodeid, filterspec, property,
+        size=None, height=None, showid=0, additional=[], **conditions):
     ''' For a Link/Multilink property, display a menu of the available
         choices
 
@@ -294,7 +303,8 @@ def do_menu(client, classname, cl, props, nodeid, filterspec, property, size=Non
     return _('[Menu: not a link]')
 
 #XXX deviates from spec
-def do_link(client, classname, cl, props, nodeid, filterspec, property=None, is_download=0, showid=0):
+def do_link(client, classname, cl, props, nodeid, filterspec, property=None,
+        is_download=0, showid=0):
     '''For a Link or Multilink property, display the names of the linked
        nodes, hyperlinked to the item views on those nodes.
        For other properties, link to this node with the property as the
@@ -364,7 +374,8 @@ def do_link(client, classname, cl, props, nodeid, filterspec, property=None, is_
             value =  _('[no %(propname)s]')%{'propname':property.capitalize()}
         return '<a href="%s%s">%s</a>'%(classname, nodeid, value)
 
-def do_count(client, classname, cl, props, nodeid, filterspec, property, **args):
+def do_count(client, classname, cl, props, nodeid, filterspec, property,
+        **args):
     ''' for a Multilink property, display a count of the number of links in
         the list
     '''
@@ -380,7 +391,8 @@ def do_count(client, classname, cl, props, nodeid, filterspec, property, **args)
     return str(len(value))
 
 # XXX pretty is definitely new ;)
-def do_reldate(client, classname, cl, props, nodeid, filterspec, property, pretty=0):
+def do_reldate(client, classname, cl, props, nodeid, filterspec, property,
+        pretty=0):
     ''' display a Date property in terms of an interval relative to the
         current date (e.g. "+ 3w", "- 2d").
 
@@ -408,16 +420,18 @@ def do_reldate(client, classname, cl, props, nodeid, filterspec, property, prett
         return interval.pretty()
     return str(interval)
 
-def do_download(client, classname, cl, props, nodeid, filterspec, property, **args):
+def do_download(client, classname, cl, props, nodeid, filterspec, property,
+        **args):
     ''' show a Link("file") or Multilink("file") property using links that
         allow you to download files
     '''
     if not nodeid:
         return _('[Download: not called from item]')
-    return do_link(client, classname, cl, props, nodeid, filterspec, property, is_download=1)
-
+    return do_link(client, classname, cl, props, nodeid, filterspec, property,
+        is_download=1)
 
-def do_checklist(client, classname, cl, props, nodeid, filterspec, property, sortby=None):
+def do_checklist(client, classname, cl, props, nodeid, filterspec, property,
+        sortby=None):
     ''' for a Link or Multilink property, display checkboxes for the
         available choices to permit filtering
 
@@ -498,7 +512,8 @@ def do_note(client, classname, cl, props, nodeid, filterspec, rows=5, cols=80):
         '</textarea>'%(rows, cols)
 
 # XXX new function
-def do_list(client, classname, cl, props, nodeid, filterspec, property, reverse=0, xtracols=None):
+def do_list(client, classname, cl, props, nodeid, filterspec, property,
+        reverse=0, xtracols=None):
     ''' list the items specified by property using the standard index for
         the class
     '''
@@ -523,7 +538,8 @@ def do_list(client, classname, cl, props, nodeid, filterspec, property, reverse=
         write_save = client.write
         client.write = fp.write
         client.listcontext = ('%s%s' % (classname, nodeid), property)
-        index = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES, propcl.classname)
+        index = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES,
+            propcl.classname)
         index.render(nodeids=value, show_display_form=0, xtracols=xtracols)
     finally:
         client.listcontext = None
@@ -532,7 +548,8 @@ def do_list(client, classname, cl, props, nodeid, filterspec, property, reverse=
     return fp.getvalue()
 
 # XXX new function
-def do_history(client, classname, cl, props, nodeid, filterspec, direction='descending'):
+def do_history(client, classname, cl, props, nodeid, filterspec,
+        direction='descending'):
     ''' list the history of the item
 
         If "direction" is 'descending' then the most recent event will
@@ -694,8 +711,8 @@ def do_submit(client, classname, cl, props, nodeid, filterspec, value=None):
     else:
         return _('[Submit: not called from item]')
 
-def do_classhelp(client, classname, cl, props, nodeid, filterspec, clname, properties, label='?', width='400',
-        height='400'):
+def do_classhelp(client, classname, cl, props, nodeid, filterspec, clname,
+        properties, label='?', width='400', height='400'):
     '''pop up a javascript window with class help
 
        This generates a link to a popup window which displays the 
@@ -710,7 +727,8 @@ def do_classhelp(client, classname, cl, props, nodeid, filterspec, clname, prope
         'properties=%s\', \'%s\', \'%s\')"><b>(%s)</b></a>'%(clname,
         properties, width, height, label)
 
-def do_email(client, classname, cl, props, nodeid, filterspec, property, escape=0):
+def do_email(client, classname, cl, props, nodeid, filterspec, property,
+        escape=0):
     '''display the property as one or more "fudged" email addrs
     '''
     
@@ -738,7 +756,9 @@ def do_email(client, classname, cl, props, nodeid, filterspec, property, escape=
         value = cgi.escape(value)
     return value
 
-def do_filterspec(client, classname, cl, props, nodeid, filterspec, classprop, urlprop):
+def do_filterspec(client, classname, cl, props, nodeid, filterspec, classprop,
+        urlprop):
+
     qs = cl.get(nodeid, urlprop)
     classname = cl.get(nodeid, classprop)
     filterspec = {}
@@ -751,7 +771,8 @@ def do_filterspec(client, classname, cl, props, nodeid, filterspec, classprop, u
     for k,v in query.items():
         if k[0] != ':':
             filterspec[k] = v
-    ixtmplt = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES, classname)
+    ixtmplt = htmltemplate.IndexTemplate(client, client.instance.TEMPLATES,
+        classname)
     qform = '<form onSubmit="return submit_once()" action="%s%s">\n'%(
         classname,nodeid)
     qform += ixtmplt.filter_form(search_text,
@@ -764,9 +785,16 @@ def do_filterspec(client, classname, cl, props, nodeid, filterspec, classprop, u
                                  pagesize)
     return qform + '</table>\n'
 
-def do_href(client, classname, cl, props, nodeid, filterspec, property, prefix='', suffix='', label=''):
+def do_href(client, classname, cl, props, nodeid, filterspec, property,
+        prefix='', suffix='', label=''):
+    ''' Generate a link to the value of the property, with the form:
+
+            <a href="[prefix][value][suffix]">[label]</a>
+
+        where the [value] is the specified property value.
+    '''
     value = determine_value(cl, props, nodeid, filterspec, property)
-    return '<a href="%s%s%s">%s</a>' % (prefix, value, suffix, label)
+    return '<a href="%s%s%s">%s</a>'%(prefix, value, suffix, label)
 
 def do_remove(client, classname, cl, props, nodeid, filterspec):
     ''' put a remove href for an item in a list '''
@@ -776,7 +804,11 @@ def do_remove(client, classname, cl, props, nodeid, filterspec):
         parentdesignator, mlprop = client.listcontext
     except (AttributeError, TypeError):
         return _('[Remove not called form listing of multilink]')
-    return '<a href="remove?:target=%s%s&:multilink=%s:%s">[Remove]</a>' % (classname, nodeid, parentdesignator, mlprop)
-
-    
-    
+    return '<a href="remove?:target=%s%s&:multilink=%s:%s">[Remove]</a>'%(
+        classname, nodeid, parentdesignator, mlprop)
+
+#
+# $Log: not supported by cvs2svn $
+#
+#
+# vim: set filetype=python ts=4 sw=4 et si