Skip to content

Commit b45ac1f

Browse files
author
Gordon B. McMillan
committed
Saving, running & editing queries.
1 parent ee2a7c4 commit b45ac1f

File tree

7 files changed

+304
-79
lines changed

7 files changed

+304
-79
lines changed

roundup/backends/back_metakit.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,11 @@ def isReadOnly(self):
166166
return self.__RW == 0
167167
def getWriteAccess(self):
168168
if self.journaltag is not None and self.__RW == 0:
169-
now = time.time
170-
start = now()
169+
#now = time.time
170+
#start = now()
171171
self._db = None
172172
#print "closing the file took %2.2f secs" % (now()-start)
173-
start = now()
173+
#start = now()
174174
self._db = metakit.storage(self.dbnm, 1)
175175
self.__RW = 1
176176
self.hist = self._db.view('history')
@@ -504,15 +504,18 @@ def setkey(self, propname):
504504
# first setkey for this run
505505
self.keyname = propname
506506
iv = self.db._db.view('_%s' % self.classname)
507-
if self.db.fastopen or iv.structure():
507+
if self.db.fastopen and iv.structure():
508508
return
509509
# very first setkey ever
510+
self.db.getWriteAccess()
511+
self.db.dirty = 1
510512
iv = self.db._db.getas('_%s[k:S,i:I]' % self.classname)
511513
iv = iv.ordered(1)
512514
#XXX
513515
# print "setkey building index"
514516
for row in self.getview():
515517
iv.append(k=getattr(row, propname), i=row.id)
518+
self.db.commit()
516519
def getkey(self):
517520
return self.keyname
518521
def lookup(self, keyvalue):
@@ -601,7 +604,10 @@ def addprop(self, **properties):
601604
if self.ruprops.has_key(key):
602605
raise ValueError, "%s is already a property of %s" % (key, self.classname)
603606
self.ruprops.update(properties)
607+
self.db.getWriteAccess()
608+
self.db.fastopen = 0
604609
view = self.__getview()
610+
self.db.commit()
605611
# ---- end of ping's spec
606612
def filter(self, search_matches, filterspec, sort, group):
607613
# search_matches is None or a set (dict of {nodeid: {propname:[nodeid,...]}})
@@ -821,26 +827,27 @@ def rollbackaction(self, action):
821827
def __getview(self):
822828
db = self.db._db
823829
view = db.view(self.classname)
824-
if self.db.fastopen:
830+
mkprops = view.structure()
831+
if mkprops and self.db.fastopen:
825832
return view.ordered(1)
826833
# is the definition the same?
827-
mkprops = view.structure()
828834
for nm, rutyp in self.ruprops.items():
829835
for mkprop in mkprops:
830836
if mkprop.name == nm:
831837
break
832838
else:
833839
mkprop = None
834840
if mkprop is None:
835-
#print "%s missing prop %s (%s)" % (self.classname, nm, rutyp.__class__.__name__)
841+
print "%s missing prop %s (%s)" % (self.classname, nm, rutyp.__class__.__name__)
836842
break
837843
if _typmap[rutyp.__class__] != mkprop.type:
838-
#print "%s - prop %s (%s) has wrong mktyp (%s)" % (self.classname, nm, rutyp.__class__.__name__, mkprop.type)
844+
print "%s - prop %s (%s) has wrong mktyp (%s)" % (self.classname, nm, rutyp.__class__.__name__, mkprop.type)
839845
break
840846
else:
841847
return view.ordered(1)
842848
# need to create or restructure the mk view
843849
# id comes first, so MK will order it for us
850+
self.db.getWriteAccess()
844851
self.db.dirty = 1
845852
s = ["%s[id:I" % self.classname]
846853
for nm, rutyp in self.ruprops.items():
@@ -849,7 +856,8 @@ def __getview(self):
849856
if mktyp == 'V':
850857
s[-1] += ('[fid:I]')
851858
s.append('_isdel:I,activity:I,creation:I,creator:I]')
852-
v = db.getas(','.join(s))
859+
v = self.db._db.getas(','.join(s))
860+
self.db.commit()
853861
return v.ordered(1)
854862
def getview(self, RW=0):
855863
if RW and self.db.isReadOnly():

roundup/cgi_client.py

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: cgi_client.py,v 1.140 2002-07-14 23:17:15 richard Exp $
18+
# $Id: cgi_client.py,v 1.141 2002-07-17 12:39:10 gmcm Exp $
1919

2020
__doc__ = """
2121
WWW request handler (also used in the stand-alone server).
@@ -193,6 +193,29 @@ def pagehead(self, title, message=None):
193193
_('Unassigned <a href="issue?assignedto=-1&status=-1,unread,deferred,chatting,need-eg,in-progress,testing,done-cbb&:sort=-activity&:filter=status,assignedto&:columns=id,activity,status,title,assignedto&:group=priority&show_customization=1">Issues</a>')
194194
]
195195

196+
if userid:
197+
# add any personal queries to the menu
198+
try:
199+
queries = self.db.getclass('query')
200+
except KeyError:
201+
# no query class
202+
queries = self.instance.dbinit.Class(self.db,
203+
"query",
204+
klass=hyperdb.String(),
205+
name=hyperdb.String(),
206+
url=hyperdb.String())
207+
queries.setkey('name')
208+
#queries.disableJournalling()
209+
try:
210+
qids = self.db.getclass('user').get(userid, 'queries')
211+
except KeyError, e:
212+
#self.db.getclass('user').addprop(queries=hyperdb.Multilink('query'))
213+
qids = []
214+
for qid in qids:
215+
links.append('<a href=%s?%s>%s</a>' % (queries.get(qid, 'klass'),
216+
queries.get(qid, 'url'),
217+
queries.get(qid, 'name')))
218+
196219
# if they're logged in, include links to their information, and the
197220
# ability to add an issue
198221
if user_name not in ('', 'anonymous'):
@@ -222,7 +245,7 @@ def pagehead(self, title, message=None):
222245
admin_links = ''
223246
if user_name == 'admin':
224247
links.append(_('<a href="list_classes">Class List</a>'))
225-
links.append(_('<a href="user">User List</a>'))
248+
links.append(_('<a href="user?:sort=username">User List</a>'))
226249
links.append(_('<a href="newuser">Add User</a>'))
227250

228251
# add the search links
@@ -251,11 +274,14 @@ def pagehead(self, title, message=None):
251274
<body bgcolor=#ffffff>
252275
%(message)s
253276
<table width=100%% border=0 cellspacing=0 cellpadding=2>
254-
<tr class="location-bar"><td><big><strong>%(title)s</strong></big></td>
255-
<td align=right valign=bottom>%(user_name)s</td></tr>
256-
<tr class="location-bar">
257-
<td align=left>%(links)s</td>
258-
<td align=right>%(user_info)s</td>
277+
<tr class="location-bar">
278+
<td><big><strong>%(title)s</strong></big></td>
279+
<td align=right valign=bottom>%(user_name)s</td>
280+
</tr>
281+
<tr class="location-bar">
282+
<td align=left>%(links)s</td>
283+
<td align=right>%(user_info)s</td>
284+
</tr>
259285
</table><br>
260286
''')%locals())
261287

@@ -330,14 +356,17 @@ def index_sort(self):
330356
x.append('%s%s' % (desc, colnm))
331357
return x
332358

333-
def index_filterspec(self, filter):
359+
def index_filterspec(self, filter, classname=None):
334360
''' pull the index filter spec from the form
335361
336362
Links and multilinks want to be lists - the rest are straight
337363
strings.
338364
'''
365+
if classname is None:
366+
classname = self.classname
367+
klass = self.db.getclass(classname)
339368
filterspec = {}
340-
props = self.db.classes[self.classname].getprops()
369+
props = klass.getprops()
341370
for colnm in filter:
342371
widget = ':%s_fs' % colnm
343372
try:
@@ -486,6 +515,34 @@ def list(self, sort=None, group=None, filter=None, columns=None,
486515
else:
487516
startwith = 0
488517

518+
if self.form.has_key('Query') and self.form['Query'].value == 'Save':
519+
# format a query string
520+
qd = {}
521+
qd[':sort'] = ','.join(map(urllib.quote, sort))
522+
qd[':group'] = ','.join(map(urllib.quote, group))
523+
qd[':filter'] = ','.join(map(urllib.quote, filter))
524+
qd[':columns'] = ','.join(map(urllib.quote, columns))
525+
for k, l in filterspec.items():
526+
qd[urllib.quote(k)] = ','.join(map(urllib.quote, l))
527+
url = '&'.join([k+'='+v for k,v in qd.items()])
528+
url += '&:pagesize=%s' % pagesize
529+
if search_text:
530+
url += '&search_text=%s' % search_text
531+
532+
# create a query
533+
d = {}
534+
d['name'] = self.form[':name'].value
535+
d['klass'] = self.form[':classname'].value
536+
d['url'] = url
537+
qid = self.db.getclass('query').create(**d)
538+
539+
# and add it to the user's query multilink
540+
uid = self.getuid()
541+
usercl = self.db.getclass('user')
542+
queries = usercl.get(uid, 'queries')
543+
queries.append(qid)
544+
usercl.set(uid, queries=queries)
545+
489546
index = htmltemplate.IndexTemplate(self, self.instance.TEMPLATES, cn)
490547
try:
491548
index.render(filterspec, search_text, filter, columns, sort,
@@ -665,6 +722,56 @@ def shownode(self, message=None, num_re=re.compile('^\d+$')):
665722
showmsg = shownode
666723
searchissue = searchnode
667724

725+
def showquery(self):
726+
queries = self.db.getclass(self.classname)
727+
if self.form.keys():
728+
sort = self.index_sort()
729+
group = self.index_arg(':group')
730+
filter = self.index_arg(':filter')
731+
columns = self.index_arg(':columns')
732+
filterspec = self.index_filterspec(filter, queries.get(self.nodeid, 'klass'))
733+
if self.form.has_key('search_text'):
734+
search_text = self.form['search_text'].value
735+
else:
736+
search_text = ''
737+
if self.form.has_key(':pagesize'):
738+
pagesize = int(self.form[':pagesize'].value)
739+
else:
740+
pagesize = 50
741+
# format a query string
742+
qd = {}
743+
qd[':sort'] = ','.join(map(urllib.quote, sort))
744+
qd[':group'] = ','.join(map(urllib.quote, group))
745+
qd[':filter'] = ','.join(map(urllib.quote, filter))
746+
qd[':columns'] = ','.join(map(urllib.quote, columns))
747+
for k, l in filterspec.items():
748+
qd[urllib.quote(k)] = ','.join(map(urllib.quote, l))
749+
url = '&'.join([k+'='+v for k,v in qd.items()])
750+
url += '&:pagesize=%s' % pagesize
751+
if search_text:
752+
url += '&search_text=%s' % search_text
753+
qname = self.form['name'].value
754+
chgd = []
755+
if qname != queries.get(self.nodeid, 'name'):
756+
chgd.append('name')
757+
if url != queries.get(self.nodeid, 'url'):
758+
chgd.append('url')
759+
if chgd:
760+
queries.set(self.nodeid, name=qname, url=url)
761+
message = _('%(changes)s edited ok')%{'changes': ', '.join(chgd)}
762+
else:
763+
message = _('nothing changed')
764+
else:
765+
message = None
766+
nm = queries.get(self.nodeid, 'name')
767+
self.pagehead('%s: %s'%(self.classname.capitalize(), nm), message)
768+
769+
# use the template to display the item
770+
item = htmltemplate.ItemTemplate(self, self.instance.TEMPLATES,
771+
self.classname)
772+
item.render(self.nodeid)
773+
self.pagefoot()
774+
668775
def _changenode(self, props):
669776
''' change the node based on the contents of the form
670777
'''
@@ -954,7 +1061,7 @@ def showuser(self, message=None, num_re=re.compile('^\d+$')):
9541061

9551062
if self.user not in ('admin', node_user):
9561063
raise Unauthorised
957-
1064+
9581065
#
9591066
# perform any editing
9601067
#
@@ -1497,6 +1604,9 @@ def parsePropsFromForm(db, cl, form, nodeid=0, num_re=re.compile('^\d+$')):
14971604

14981605
#
14991606
# $Log: not supported by cvs2svn $
1607+
# Revision 1.140 2002/07/14 23:17:15 richard
1608+
# cleaned up structure
1609+
#
15001610
# Revision 1.139 2002/07/14 06:14:40 richard
15011611
# Some more TODOs
15021612
#

0 commit comments

Comments
 (0)