Code

Add Number and Boolean types to hyperdb.
authorgmcm <gmcm@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 18 Jul 2002 11:17:31 +0000 (11:17 +0000)
committergmcm <gmcm@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 18 Jul 2002 11:17:31 +0000 (11:17 +0000)
Add conversion cases to web, mail & admin interfaces.
Add storage/serialization cases to back_anydbm & back_metakit.

git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@892 57a73879-2fb5-44c3-a270-3262357dd7e2

roundup/admin.py
roundup/backends/back_anydbm.py
roundup/backends/back_metakit.py
roundup/cgi_client.py
roundup/htmltemplate.py
roundup/hyperdb.py
roundup/indexer.py
roundup/mailgw.py

index b8cfb840bb81fce6cfcd55b24849d76940b65354..b213c14d70624d8cee19dcd3cfc038ae3694fa89 100644 (file)
@@ -16,7 +16,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: admin.py,v 1.17 2002-07-14 06:05:50 richard Exp $
+# $Id: admin.py,v 1.18 2002-07-18 11:17:30 gmcm Exp $
 
 import sys, os, getpass, getopt, re, UserDict, shlex, shutil
 try:
@@ -439,6 +439,10 @@ Command help:
                     props[key] = value
                 elif isinstance(proptype, hyperdb.Multilink):
                     props[key] = value.split(',')
+                elif isinstance(proptype, hyperdb.Boolean):
+                    props[key] = value.lower() in ('yes', 'true', 'on', '1')
+                elif isinstance(proptype, hyperdb.Number):
+                    props[key] = int(value)
 
             # try the set
             try:
@@ -611,6 +615,10 @@ Command help:
                 props[propname] = password.Password(value)
             elif isinstance(proptype, hyperdb.Multilink):
                 props[propname] = value.split(',')
+            elif isinstance(proptype, hyperdb.Boolean):
+                props[propname] = value.lower() in ('yes', 'true', 'on', '1')
+            elif isinstance(proptype, hyperdb.Number):
+                props[propname] = int(value)
 
         # check for the key property
         propname = cl.getkey()
@@ -1123,6 +1131,9 @@ if __name__ == '__main__':
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.17  2002/07/14 06:05:50  richard
+#  . fixed the date module so that Date(". - 2d") works
+#
 # Revision 1.16  2002/07/09 04:19:09  richard
 # Added reindex command to roundup-admin.
 # Fixed reindex on first access.
index 29bae6e2e7625e1ad03c867421d345ad7dab1a95..0e56bcc5fce6804f41e8822612ae3be7c5945594 100644 (file)
@@ -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.47 2002-07-14 23:18:20 richard Exp $
+#$Id: back_anydbm.py,v 1.48 2002-07-18 11:17:31 gmcm 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
@@ -29,7 +29,7 @@ from blobfiles import FileStorage
 from roundup.indexer import Indexer
 from locking import acquire_lock, release_lock
 from roundup.hyperdb import String, Password, Date, Interval, Link, \
-    Multilink, DatabaseError
+    Multilink, DatabaseError, Boolean, Number
 
 #
 # Now the database
@@ -730,6 +730,18 @@ class Class(hyperdb.Class):
                 if value is not None and not isinstance(value, date.Interval):
                     raise TypeError, 'new property "%s" not an Interval'%key
 
+            elif isinstance(prop, Number):
+                try:
+                    int(value)
+                except TypeError:
+                    raise TypeError, 'new property "%s" not numeric' % propname
+
+            elif isinstance(prop, Boolean):
+                try:
+                    int(value)
+                except TypeError:
+                    raise TypeError, 'new property "%s" is not boolean' % propname
+
         # make sure there's data where there needs to be
         for key, prop in self.properties.items():
             if propvalues.has_key(key):
@@ -1011,6 +1023,18 @@ class Class(hyperdb.Class):
                         'Interval'%propname
                 propvalues[propname] = value
 
+            elif value is not None and isinstance(prop, Number):
+                try:
+                    int(value)
+                except TypeError:
+                    raise TypeError, 'new property "%s" not numeric' % propname
+
+            elif value is not None and isinstance(prop, Boolean):
+                try:
+                    int(value)
+                except TypeError:
+                    raise TypeError, 'new property "%s" not boolean' % propname
+
             node[propname] = value
 
         # nothing to do?
@@ -1291,6 +1315,14 @@ class Class(hyperdb.Class):
                 v = v.replace('?', '.')
                 v = v.replace('*', '.*?')
                 l.append((2, k, re.compile(v, re.I)))
+            elif isinstance(propclass, Boolean):
+                if type(v) is type(''):
+                    bv = v.lower() in ('yes', 'true', 'on', '1')
+                else:
+                    bv = v
+                l.append((6, k, bv))
+            elif isinstance(propclass, Number):
+                l.append((6, k, int(v)))
             else:
                 l.append((6, k, v))
         filterspec = l
@@ -1456,6 +1488,12 @@ class Class(hyperdb.Class):
                         elif dir == '-':
                             r = cmp(len(bv), len(av))
                             if r != 0: return r
+                    elif isinstance(propclass, Number) or isinstance(propclass, Boolean):
+                        if dir == '+':
+                            r = cmp(av, bv)
+                        elif dir == '-':
+                            r = cmp(bv, av)
+                        
                 # end for dir, prop in list:
             # end for list in sort, group:
             # if all else fails, compare the ids
@@ -1638,6 +1676,10 @@ class IssueClass(Class, roundupdb.IssueClass):
 
 #
 #$Log: not supported by cvs2svn $
+#Revision 1.47  2002/07/14 23:18:20  richard
+#. fixed the journal bloat from multilink changes - we just log the add or
+#  remove operations, not the whole list
+#
 #Revision 1.46  2002/07/14 06:06:34  richard
 #Did some old TODOs
 #
index 1c93af77592aa747a41b08f153f75cd3800c10d1..6936ea288cb84651d698b8eb92e07f81a39a6cf3 100755 (executable)
@@ -455,6 +455,17 @@ class Class:
                 setattr(row, key, str(value))
                 changes[key] = str(oldvalue)
                 propvalues[key] = str(value)
+                
+            elif value is not None and isinstance(prop, hyperdb.Number):
+                setattr(row, key, int(value))
+                changes[key] = oldvalue
+                propvalues[key] = value
+                
+            elif value is not None and isinstance(prop, hyperdb.Boolean):
+                bv = value != 0
+                setattr(row, key, bv)
+                changes[key] = oldvalue
+                propvalues[key] = value
 
             oldnode[key] = oldvalue
 
@@ -661,6 +672,14 @@ class Class:
                 regexes[propname] = re.compile(v, re.I)
             elif propname == 'id':
                 where[propname] = int(value)
+            elif isinstance(prop, hyperdb.Boolean):
+                if type(value) is _STRINGTYPE:
+                    bv = value.lower() in ('yes', 'true', 'on', '1')
+                else:
+                    bv = value
+                where[propname] = bv
+            elif isinstance(prop, hyperdb.Number):
+                where[propname] = int(value)
             else:
                 where[propname] = str(value)
         v = self.getview()
@@ -891,6 +910,8 @@ _converters = {
     hyperdb.Multilink : _fetchML,
     hyperdb.Interval  : date.Interval,
     hyperdb.Password  : _fetchPW,
+    hyperdb.Boolean   : lambda n: n,
+    hyperdb.Number    : lambda n: n,
 }                
 
 class FileName(hyperdb.String):
@@ -904,6 +925,8 @@ _typmap = {
     hyperdb.Multilink : 'V',
     hyperdb.Interval  : 'S',
     hyperdb.Password  : 'S',
+    hyperdb.Boolean   : 'I',
+    hyperdb.Number    : 'I',
 }
 class FileClass(Class):
     ' like Class but with a content property '
index 2bc7922c7c85628af767990a5cf40152436a4754..715d02d61bd035b9fb0eecd1305fcf3aaa065041 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.141 2002-07-17 12:39:10 gmcm Exp $
+# $Id: cgi_client.py,v 1.142 2002-07-18 11:17:30 gmcm Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -1585,6 +1585,12 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
                 l.append(entry)
             l.sort()
             value = l
+        elif isinstance(proptype, hyperdb.Boolean):
+            value = form[key].value.strip()
+            props[key] = value = value.lower() in ('yes', 'true', 'on', '1')
+        elif isinstance(proptype, hyperdb.Number):
+            value = form[key].value.strip()
+            props[key] = value = int(value)
 
         # get the old value
         if nodeid:
@@ -1604,6 +1610,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.141  2002/07/17 12:39:10  gmcm
+# Saving, running & editing queries.
+#
 # Revision 1.140  2002/07/14 23:17:15  richard
 # cleaned up structure
 #
index e88690157f6f7e6412fb666489dec049b80cabb1..0b930c5f0187aedf5b4a6e8ba26efe0ff9d608d0 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.100 2002-07-18 07:01:54 richard Exp $
+# $Id: htmltemplate.py,v 1.101 2002-07-18 11:17:30 gmcm Exp $
 
 __doc__ = """
 Template engine.
@@ -107,6 +107,10 @@ class TemplateFunctions:
             value = str(value)
         elif isinstance(propclass, hyperdb.Interval):
             value = str(value)
+        elif isinstance(propclass, hyperdb.Number):
+            value = str(value)
+        elif isinstance(propclass, hyperdb.Boolean):
+            value = value and "Yes" or "No"
         elif isinstance(propclass, hyperdb.Link):
             if value:
                 if lookup:
@@ -199,6 +203,11 @@ class TemplateFunctions:
                 value = cgi.escape(str(value))
                 value = '&quot;'.join(value.split('"'))
             s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
+        elif isinstance(propclass, hyperdb.Boolean):
+            checked = value and "checked" or ""
+            s = '<input type="checkbox" name="%s" %s>'%(property, checked)
+        elif isinstance(propclass, hyperdb.Number):
+            s = '<input name="%s" value="%s" size="%s">'%(property, value, size)
         elif isinstance(propclass, hyperdb.Password):
             s = '<input type="password" name="%s" size="%s">'%(property, size)
         elif isinstance(propclass, hyperdb.Link):
@@ -268,7 +277,7 @@ class TemplateFunctions:
             property, rows, cols, value)
 
     def do_menu(self, property, size=None, height=None, showid=0,
-            additional=[]):
+            additional=[], **conditions):
         ''' For a Link/Multilink property, display a menu of the available
             choices
 
@@ -297,8 +306,8 @@ class TemplateFunctions:
             if linkcl.getprops().has_key('order'):  
                 sort_on = 'order'  
             else:  
-                sort_on = linkcl.labelprop()  
-            options = linkcl.filter(None, {}, [sort_on], []) 
+                sort_on = linkcl.labelprop()
+            options = linkcl.filter(None, conditions, [sort_on], []) 
             height = height or min(len(options), 7)
             l = ['<select multiple name="%s" size="%s">'%(property, height)]
             k = linkcl.labelprop(1)
@@ -337,8 +346,8 @@ class TemplateFunctions:
             if linkcl.getprops().has_key('order'):  
                 sort_on = 'order'  
             else:  
-                sort_on = linkcl.labelprop()  
-            options = linkcl.filter(None, {}, [sort_on], []) 
+                sort_on = linkcl.labelprop() 
+            options = linkcl.filter(None, conditions, [sort_on], []) 
             for optionid in options:
                 option = linkcl.get(optionid, k)
                 s = ''
@@ -1135,6 +1144,18 @@ class IndexTemplate(TemplateFunctions):
                 op = "equals&nbsp;"
                 xtra = ""
                 val = filterspec.get(nm, '')
+            elif isinstance(propdescr, hyperdb.Boolean):
+                op = "is&nbsp;"
+                xtra = ""
+                val = filterspec.get(nm, None)
+                if val is not None:
+                    val = 'True' and val or 'False'
+                else:
+                    val = ''
+            elif isinstance(propdescr, hyperdb.Number):
+                op = "equals&nbsp;"
+                xtra = ""
+                val = str(filterspec.get(nm, ''))
             else:
                 w('<td></td><td></td><td></td></tr>')
                 continue
@@ -1341,6 +1362,9 @@ class NewItemTemplate(TemplateFunctions):
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.100  2002/07/18 07:01:54  richard
+# minor bugfix
+#
 # Revision 1.99  2002/07/17 12:39:10  gmcm
 # Saving, running & editing queries.
 #
index 3f6429f82b510adb18f6af68bc30ecf5d17dc11d..2905166251310174fca98b8f340bb247d90ec462 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: hyperdb.py,v 1.75 2002-07-14 02:05:53 richard Exp $
+# $Id: hyperdb.py,v 1.76 2002-07-18 11:17:30 gmcm Exp $
 
 __doc__ = """
 Hyperdatabase implementation, especially field types.
@@ -110,6 +110,17 @@ class Multilink:
         ' more useful for dumps '
         return '<%s to "%s">'%(self.__class__, self.classname)
 
+class Boolean:
+    """An object designating a boolean property"""
+    def __repr__(self):
+        'more useful for dumps'
+        return '<%s>' % self.__class__
+    
+class Number:
+    """An object designating a numeric property"""
+    def __repr__(self):
+        'more useful for dumps'
+        return '<%s>' % self.__class__
 #
 # Support for splitting designators
 #
@@ -580,6 +591,9 @@ def Choice(name, db, *options):
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.75  2002/07/14 02:05:53  richard
+# . all storage-specific code (ie. backend) is now implemented by the backends
+#
 # Revision 1.74  2002/07/10 00:24:10  richard
 # braino
 #
index 814425a5848798585704549ad35f965be45e19c8..35e5a2990ba0f6da40b5171fcb977d4bc3f9ecfa 100644 (file)
@@ -14,7 +14,7 @@
 #     that promote freedom, but obviously am giving up any rights
 #     to compel such.
 # 
-#$Id: indexer.py,v 1.10 2002-07-14 23:17:24 richard Exp $
+#$Id: indexer.py,v 1.11 2002-07-18 11:17:30 gmcm Exp $
 '''
 This module provides an indexer class, RoundupIndexer, that stores text
 indices in a roundup instance.  This class makes searching the content of
@@ -49,7 +49,7 @@ class Indexer:
         elif os.path.exists(version):
             version = open(version).read()
             # check the value and reindex if it's not the latest
-            if version != '1':
+            if version.strip() != '1':
                 self.force_reindex()
 
     def force_reindex(self):
@@ -333,6 +333,9 @@ class Indexer:
 
 #
 #$Log: not supported by cvs2svn $
+#Revision 1.10  2002/07/14 23:17:24  richard
+#oops
+#
 #Revision 1.9  2002/07/14 06:11:16  richard
 #Some TODOs
 #
index 6ea92ffbfe2551fe5650f0fab3f05aa27bc31c5d..b5d802d150b6b2af0db135c5cd50c5c3536c30be 100644 (file)
@@ -73,7 +73,7 @@ are calling the create() method to create a new node). If an auditor raises
 an exception, the original message is bounced back to the sender with the
 explanatory message given in the exception. 
 
-$Id: mailgw.py,v 1.76 2002-07-10 06:39:37 richard Exp $
+$Id: mailgw.py,v 1.77 2002-07-18 11:17:31 gmcm Exp $
 '''
 
 
@@ -491,6 +491,12 @@ Subject was: "%s"
                         props[propname] = newvalue
                     else:
                         props[propname] = curvalue
+                elif isinstance(proptype, hyperdb.Boolean):
+                    value = value.strip()
+                    props[propname] = value.lower() in ('yes', 'true', 'on', '1')
+                elif isinstance(proptype, hyperdb.Number):
+                    value = value.strip()
+                    props[propname] = int(value)
 
             # handle any errors parsing the argument list
             if errors:
@@ -784,6 +790,9 @@ def parseContent(content, keep_citations, keep_body,
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.76  2002/07/10 06:39:37  richard
+#  . made mailgw handle set and modify operations on multilinks (bug #579094)
+#
 # Revision 1.75  2002/07/09 01:21:24  richard
 # Added ability for unit tests to turn off exception handling in mailgw so
 # that exceptions are reported earlier (and hence make sense).