Code

Sending of PGP-Encrypted mail to all users or selected users (via roles)
[roundup.git] / roundup / backends / rdbms_common.py
index 09425b2ac35ce557ac24c11d5f93829cb8fbd827..ebbb648a08d94db82f0f966d2cd30b9fd9b3dd47 100644 (file)
@@ -812,6 +812,8 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
             description="User is allowed to edit "+cn)
         self.security.addPermission(name="View", klass=cn,
             description="User is allowed to access "+cn)
+        self.security.addPermission(name="Retire", klass=cn,
+            description="User is allowed to retire "+cn)
 
     def getclasses(self):
         """ Return a list of the names of all existing classes.
@@ -1080,8 +1082,34 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
 
         raise ValueError('%r is not a hyperdb property class' % propklass)
 
-    def getnode(self, classname, nodeid):
+    def _materialize_multilink(self, classname, nodeid, node, propname):
+        """ evaluation of single Multilink (lazy eval may have skipped this)
+        """
+        if propname not in node:
+            sql = 'select linkid from %s_%s where nodeid=%s'%(classname,
+                propname, self.arg)
+            self.sql(sql, (nodeid,))
+            # extract the first column from the result
+            # XXX numeric ids
+            items = [int(x[0]) for x in self.cursor.fetchall()]
+            items.sort ()
+            node[propname] = [str(x) for x in items]
+
+    def _materialize_multilinks(self, classname, nodeid, node, props=None):
+        """ get all Multilinks of a node (lazy eval may have skipped this)
+        """
+        cl = self.classes[classname]
+        props = props or [pn for (pn, p) in cl.properties.iteritems()
+                          if isinstance(p, Multilink)]
+        for propname in props:
+            if propname not in node:
+                self._materialize_multilink(classname, nodeid, node, propname)
+
+    def getnode(self, classname, nodeid, fetch_multilinks=True):
         """ Get a node from the database.
+            For optimisation optionally we don't fetch multilinks
+            (lazy Multilinks).
+            But for internal database operations we need them.
         """
         # see if we have this node cached
         key = (classname, nodeid)
@@ -1091,6 +1119,8 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
             if __debug__:
                 self.stats['cache_hits'] += 1
             # return the cached information
+            if fetch_multilinks:
+                self._materialize_multilinks(classname, nodeid, self.cache[key])
             return self.cache[key]
 
         if __debug__:
@@ -1124,6 +1154,9 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
                 value = self.to_hyperdb_value(props[name].__class__)(value)
             node[name] = value
 
+        if fetch_multilinks and mls:
+            self._materialize_multilinks(classname, nodeid, node, mls)
+
         # save off in the cache
         key = (classname, nodeid)
         self._cache_save(key, node)
@@ -1297,7 +1330,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database):
                         continue
                     cvt = self.to_hyperdb_value(property.__class__)
                     if isinstance(property, Password):
-                        params[param] = cvt(value)
+                        params[param] = password.JournalPassword(value)
                     elif isinstance(property, Date):
                         params[param] = cvt(value)
                     elif isinstance(property, Interval):
@@ -1616,7 +1649,7 @@ class Class(hyperdb.Class):
             return nodeid
 
         # get the node's dict
-        d = self.db.getnode(self.classname, nodeid)
+        d = self.db.getnode(self.classname, nodeid, fetch_multilinks=False)
         # handle common case -- that property is in dict -- first
         # if None and one of creator/creation actor/activity return None
         if propname in d:
@@ -1640,14 +1673,7 @@ class Class(hyperdb.Class):
 
         # lazy evaluation of Multilink
         if propname not in d and isinstance(prop, Multilink):
-            sql = 'select linkid from %s_%s where nodeid=%s'%(self.classname,
-                propname, self.db.arg)
-            self.db.sql(sql, (nodeid,))
-            # extract the first column from the result
-            # XXX numeric ids
-            items = [int(x[0]) for x in self.db.cursor.fetchall()]
-            items.sort ()
-            d[propname] = [str(x) for x in items]
+            self.db._materialize_multilink(self.classname, nodeid, d, propname)
 
         # handle there being no value in the table for the property
         if propname not in d or d[propname] is None:
@@ -1864,6 +1890,8 @@ class Class(hyperdb.Class):
                 if not isinstance(value, password.Password):
                     raise TypeError('new property "%s" not a Password'%propname)
                 propvalues[propname] = value
+                journalvalues[propname] = \
+                    current and password.JournalPassword(current)
 
             elif value is not None and isinstance(prop, Date):
                 if not isinstance(value, date.Date):
@@ -1995,23 +2023,6 @@ class Class(hyperdb.Class):
             raise DatabaseError(_('Database open read-only'))
         self.db.destroynode(self.classname, nodeid)
 
-    def history(self, nodeid):
-        """Retrieve the journal of edits on a particular node.
-
-        'nodeid' must be the id of an existing node of this class or an
-        IndexError is raised.
-
-        The returned list contains tuples of the form
-
-            (nodeid, date, tag, action, params)
-
-        'date' is a Timestamp object specifying the time of the change and
-        'tag' is the journaltag specified when the database was opened.
-        """
-        if not self.do_journal:
-            raise ValueError('Journalling is disabled for this class')
-        return self.db.getjournal(self.classname, nodeid)
-
     # Locating nodes:
     def hasnode(self, nodeid):
         """Determine if the given nodeid actually exists