Code

use the upload-supplied content-type if there is one
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Tue, 20 Jan 2004 03:58:38 +0000 (03:58 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Tue, 20 Jan 2004 03:58:38 +0000 (03:58 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2054 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
TODO.txt
roundup/backends/back_mysql.py
roundup/backends/rdbms_common.py
roundup/cgi/client.py
roundup/indexer.py
test/db_test_base.py

index 7a9743f1075fd0465cedef3fb18312f839056e4d..a4a6dea0644565ce5ecc3c2091cba7f43f9a6ce1 100644 (file)
@@ -50,6 +50,7 @@ Fixed:
 - the mail gateway now searches recursively for the text/plain and the
   attachments of a message (sf bug 841241).
 - fixed display of feedback messages in some situations (sf bug 739545)
+- use supplied content-type on file uploads before trying filename)
 
 Cleanup:
 - replace curuserid attribute on Database with the extended getuid() method.
index 2da8880aa62317170ca43a2e38cd46c3823db3d9..cf79d7fedd3d13c057d9ec1aa5fbd9f6cebf3187 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,6 +1,7 @@
 This file has been re-purposed to contain specifically the items that need
 doing before the next release:
 
+- add tests for group-by-multilink so I finally implement it for the RDBMSes
 - full coverage analysis for unit tests
 - migrate to numeric ID values (fixes bug 817217)
 
index fa3c6d4ccb97f50d947083bd5159e05066885105..7ead40200d1ca568ead60ad320728171f6593339 100644 (file)
@@ -411,6 +411,92 @@ class MysqlClass:
         # return the IDs (the first column)
         return [row[0] for row in l]
 
+    # mysql doesn't implement INTERSECT
+    def find(self, **propspec):
+        '''Get the ids of nodes in this class which link to the given nodes.
+
+        'propspec' consists of keyword args propname=nodeid or
+                   propname={nodeid:1, }
+        'propname' must be the name of a property in this class, or a
+                   KeyError is raised.  That property must be a Link or
+                   Multilink property, or a TypeError is raised.
+
+        Any node in this class whose 'propname' property links to any of the
+        nodeids will be returned. Used by the full text indexing, which knows
+        that "foo" occurs in msg1, msg3 and file7, so we have hits on these
+        issues:
+
+            db.issue.find(messages={'1':1,'3':1}, files={'7':1})
+        '''
+        if __debug__:
+            print >>hyperdb.DEBUG, 'find', (self, propspec)
+
+        # shortcut
+        if not propspec:
+            return []
+
+        # validate the args
+        props = self.getprops()
+        propspec = propspec.items()
+        for propname, nodeids in propspec:
+            # check the prop is OK
+            prop = props[propname]
+            if not isinstance(prop, Link) and not isinstance(prop, Multilink):
+                raise TypeError, "'%s' not a Link/Multilink property"%propname
+
+        # first, links
+        a = self.db.arg
+        where = ['__retired__ <> %s'%a]
+        allvalues = (1,)
+        for prop, values in propspec:
+            if not isinstance(props[prop], hyperdb.Link):
+                continue
+            if type(values) is type({}) and len(values) == 1:
+                values = values.keys()[0]
+            if type(values) is type(''):
+                allvalues += (values,)
+                where.append('_%s = %s'%(prop, a))
+            elif values is None:
+                where.append('_%s is NULL'%prop)
+            else:
+                allvalues += tuple(values.keys())
+                where.append('_%s in (%s)'%(prop, ','.join([a]*len(values))))
+        tables = []
+        if where:
+            tables.append('select id as nodeid from _%s where %s'%(
+                self.classname, ' and '.join(where)))
+
+        # now multilinks
+        for prop, values in propspec:
+            if not isinstance(props[prop], hyperdb.Multilink):
+                continue
+            if type(values) is type(''):
+                allvalues += (values,)
+                s = a
+            else:
+                allvalues += tuple(values.keys())
+                s = ','.join([a]*len(values))
+            tables.append('select nodeid from %s_%s where linkid in (%s)'%(
+                self.classname, prop, s))
+
+        raise NotImplemented, "XXX this code's farked"
+        d = {}
+        self.db.sql(sql, allvalues)
+        for result in self.db.sql_fetchall():
+            d[result[0]] = 1
+
+        for query in tables[1:]:
+            self.db.sql(sql, allvalues)
+            for result in self.db.sql_fetchall():
+                if not d.has_key(result[0]):
+                    continue
+
+        if __debug__:
+            print >>hyperdb.DEBUG, 'find ... ', l
+        l = d.keys()
+        l.sort()
+        return l
+
 class Class(MysqlClass, rdbms_common.Class):
     pass
 class IssueClass(MysqlClass, rdbms_common.IssueClass):
index 45078c44b0f3237e3bdcf31e4c4c89fdbcf53f94..d9e2d582b349ce80246c6fabf125a0caa81c3358 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: rdbms_common.py,v 1.72 2003-12-05 09:47:46 richard Exp $
+# $Id: rdbms_common.py,v 1.73 2004-01-20 03:58:38 richard Exp $
 ''' Relational database (SQL) backend common code.
 
 Basics:
@@ -1788,9 +1788,9 @@ class Class(hyperdb.Class):
                 raise TypeError, "'%s' not a Link/Multilink property"%propname
 
         # first, links
-        where = ['__retired__ = %s']
-        allvalues = (0,)
         a = self.db.arg
+        where = ['__retired__ <> %s'%a]
+        allvalues = (1,)
         for prop, values in propspec:
             if not isinstance(props[prop], hyperdb.Link):
                 continue
@@ -1821,7 +1821,8 @@ class Class(hyperdb.Class):
                 s = ','.join([a]*len(values))
             tables.append('select nodeid from %s_%s where linkid in (%s)'%(
                 self.classname, prop, s))
-        sql = '\nunion\n'.join(tables)
+
+        sql = '\nintersect\n'.join(tables)
         self.db.sql(sql, allvalues)
         l = [x[0] for x in self.db.sql_fetchall()]
         if __debug__:
index 372100284369582e2cd7398054f5f2d00ec35276..b53a38cd8c6d812643817ea2295eb0eec19a4a2b 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: client.py,v 1.152 2004-01-19 23:56:07 richard Exp $
+# $Id: client.py,v 1.153 2004-01-20 03:58:38 richard Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -1778,8 +1778,11 @@ You should then receive another email with the new password.
                                 props['name'] = fn
                             # use this info as the type/filename properties
                             if propdef.has_key('type'):
-                                props['type'] = mimetypes.guess_type(fn)[0]
-                                if not props['type']:
+                                if hasattr(value, 'type'):
+                                    props['type'] = value.type
+                                elif mimetypes.guess_type(fn)[0]:
+                                    props['type'] = mimetypes.guess_type(fn)[0]
+                                else:
                                     props['type'] = "application/octet-stream"
                             # finally, read the content RAW
                             value = value.value
index ef697d938f968bb475c57026124f45ad64fdfcfd..9bee8bd19e19b54d5ddb4495ae522be4302a11e7 100644 (file)
@@ -14,7 +14,7 @@
 #     that promote freedom, but obviously am giving up any rights
 #     to compel such.
 # 
-#$Id: indexer.py,v 1.16 2003-01-14 03:56:44 richard Exp $
+#$Id: indexer.py,v 1.17 2004-01-20 03:58:38 richard Exp $
 '''
 This module provides an indexer class, RoundupIndexer, that stores text
 indices in a roundup instance.  This class makes searching the content of
@@ -146,7 +146,6 @@ class Indexer:
         if not hits:
             return {}
 
-        #designator_propname = {'msg': 'messages', 'file': 'files'}
         designator_propname = {}
         for nm, propclass in klass.getprops().items():
             if isinstance(propclass, Link) or isinstance(propclass, Multilink):
@@ -154,7 +153,7 @@ class Indexer:
 
         # build a dictionary of nodes and their associated messages
         # and files
-        nodeids = {}    # this is the answer
+        nodeids = {}      # this is the answer
         propspec = {}     # used to do the klass.find
         for propname in designator_propname.values():
             propspec[propname] = {}   # used as a set (value doesn't matter)
index ed707abb1cc7c49915bd391acfabb1be7ef1e1ac..9945ef4ded0568b2f9312f56af28bc7c529324d5 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: db_test_base.py,v 1.12 2003-12-10 01:40:51 richard Exp $ 
+# $Id: db_test_base.py,v 1.13 2004-01-20 03:58:38 richard Exp $ 
 
 import unittest, os, shutil, errno, imp, sys, time, pprint
 
@@ -580,20 +580,20 @@ class DBTest(MyTestCase):
         # we should have the create and last set entries now
         self.assertEqual(jlen-1, len(self.db.getjournal('issue', id)))
 
-    def testSearching(self):
-        self.db.file.create(content='hello', type="text/plain")
-        self.db.file.create(content='world', type="text/frozz",
+    def testIndexerSearching(self):
+        f1 = self.db.file.create(content='hello', type="text/plain")
+        f2 = self.db.file.create(content='world', type="text/frozz",
             comment='blah blah')
-        self.db.issue.create(files=['1', '2'], title="flebble plop")
-        self.db.issue.create(title="flebble frooz")
+        i1 = self.db.issue.create(files=[f1, f2], title="flebble plop")
+        i2 = self.db.issue.create(title="flebble frooz")
         self.db.commit()
         self.assertEquals(self.db.indexer.search(['hello'], self.db.issue),
-            {'1': {'files': ['1']}})
+            {i1: {'files': [f1]}})
         self.assertEquals(self.db.indexer.search(['world'], self.db.issue), {})
         self.assertEquals(self.db.indexer.search(['frooz'], self.db.issue),
-            {'2': {}})
+            {i2: {}})
         self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue),
-            {'2': {}, '1': {}})
+            {i1: {}, i2: {}})
 
     def testReindexing(self):
         self.db.issue.create(title="frooz")