From a0dd55dae5864d717faf90d80addebdb3ebe0fa5 Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 20 Jan 2004 03:58:38 +0000 Subject: [PATCH] use the upload-supplied content-type if there is one git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2054 57a73879-2fb5-44c3-a270-3262357dd7e2 --- CHANGES.txt | 1 + TODO.txt | 1 + roundup/backends/back_mysql.py | 86 ++++++++++++++++++++++++++++++++ roundup/backends/rdbms_common.py | 9 ++-- roundup/cgi/client.py | 9 ++-- roundup/indexer.py | 5 +- test/db_test_base.py | 18 +++---- 7 files changed, 110 insertions(+), 19 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7a9743f..a4a6dea 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -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. diff --git a/TODO.txt b/TODO.txt index 2da8880..cf79d7f 100644 --- 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) diff --git a/roundup/backends/back_mysql.py b/roundup/backends/back_mysql.py index fa3c6d4..7ead402 100644 --- a/roundup/backends/back_mysql.py +++ b/roundup/backends/back_mysql.py @@ -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): diff --git a/roundup/backends/rdbms_common.py b/roundup/backends/rdbms_common.py index 45078c4..d9e2d58 100644 --- a/roundup/backends/rdbms_common.py +++ b/roundup/backends/rdbms_common.py @@ -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__: diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py index 3721002..b53a38c 100644 --- a/roundup/cgi/client.py +++ b/roundup/cgi/client.py @@ -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 diff --git a/roundup/indexer.py b/roundup/indexer.py index ef697d9..9bee8bd 100644 --- a/roundup/indexer.py +++ b/roundup/indexer.py @@ -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) diff --git a/test/db_test_base.py b/test/db_test_base.py index ed707ab..9945ef4 100644 --- a/test/db_test_base.py +++ b/test/db_test_base.py @@ -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") -- 2.30.2