Mercurial > p > roundup > code
changeset 627:952679be9e2c
Added simple editing for classes that don't define a templated interface.
- access using the admin "class list" interface
- limited to admin-only
- requires the csv module from object-craft (url given if it's missing)
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Wed, 20 Feb 2002 05:05:29 +0000 |
| parents | 300e17e7045c |
| children | 923de4949369 |
| files | CHANGES.txt roundup/cgi_client.py roundup/htmltemplate.py roundup/hyperdb.py |
| diffstat | 4 files changed, 132 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/CHANGES.txt Wed Feb 20 05:04:32 2002 +0000 +++ b/CHANGES.txt Wed Feb 20 05:05:29 2002 +0000 @@ -8,7 +8,10 @@ better configuration system. . Alternate email addresses are now available for users. See the MIGRATION file for info on how to activate the feature. - + . Added simple editing for classes that don't define a templated interface. + - access using the admin "class list" interface + - limited to admin-only + - requires the csv module from object-craft (url given if it's missing) Fixed: . Clean up mail handling, multipart handling. @@ -25,6 +28,7 @@ . #516854 ] "My Issues" and redisplay . #517906 ] Attribute order in "View customisation" . #514854 ] History: "User" is always ticket creator + . wasn't handling cvs parser feeding correctly 2002-01-24 - 0.4.0
--- a/roundup/cgi_client.py Wed Feb 20 05:04:32 2002 +0000 +++ b/roundup/cgi_client.py Wed Feb 20 05:05:29 2002 +0000 @@ -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.102 2002-02-15 07:08:44 richard Exp $ +# $Id: cgi_client.py,v 1.103 2002-02-20 05:05:28 richard Exp $ __doc__ = """ WWW request handler (also used in the stand-alone server). @@ -298,10 +298,88 @@ show_customization = self.customization_widget() index = htmltemplate.IndexTemplate(self, self.instance.TEMPLATES, cn) - index.render(filterspec, filter, columns, sort, group, - show_customization=show_customization) + try: + index.render(filterspec, filter, columns, sort, group, + show_customization=show_customization) + except htmltemplate.MissingTemplateError: + self.basicClassEditPage() self.pagefoot() + def basicClassEditPage(self): + '''Display a basic edit page that allows simple editing of the + nodes of the current class + ''' + if self.user != 'admin': + raise Unauthorised + w = self.write + cn = self.classname + cl = self.db.classes[cn] + props = ['id'] + cl.getprops(protected=0).keys() + + # get the CSV module + try: + import csv + except ImportError: + w(_('Sorry, you need the csv module to use this function.<br>\n' + 'Get it from: <a href="http://www.object-craft.com.au/projects/csv/">http://www.object-craft.com.au/projects/csv/')) + return + + # do the edit + if self.form.has_key('rows'): + rows = self.form['rows'].value.splitlines() + p = csv.parser() + idlessprops = props[1:] + found = {} + for row in rows: + values = p.parse(row) + # not a complete row, keep going + if not values: continue + + # extract the nodeid + nodeid, values = values[0], values[1:] + found[nodeid] = 1 + + # extract the new values + d = {} + for name, value in zip(idlessprops, values): + d[name] = value.strip() + + # perform the edit + if cl.hasnode(nodeid): + # edit existing + cl.set(nodeid, **d) + else: + # new node + found[cl.create(**d)] = 1 + + # retire the removed entries + for nodeid in cl.list(): + if not found.has_key(nodeid): + cl.retire(nodeid) + + w(_('''<p class="form-help">You may edit the contents of the + "%(classname)s" class using this form.</p> + <p class="form-help">Remove entries by deleting their line. Add + new entries by appending + them to the table - put an X in the id column.</p>''')%{'classname':cn}) + + l = [] + for name in props: + l.append(name) + w('<tt>') + w(', '.join(l) + '\n') + w('</tt>') + + w('<form onSubmit="return submit_once()" method="POST">') + w('<textarea name="rows" cols=80 rows=15>') + for nodeid in cl.list(): + l = [] + for name in props: + l.append(cgi.escape(str(cl.get(nodeid, name)))) + w(', '.join(l) + '\n') + + w(_('</textarea><br><input type="submit" value="Save Changes"></form>')) + def shownode(self, message=None): ''' display an item ''' @@ -744,7 +822,8 @@ self.write('<table border=0 cellspacing=0 cellpadding=2>\n') for cn in classnames: cl = self.db.getclass(cn) - self.write('<tr class="list-header"><th colspan=2 align=left>%s</th></tr>'%cn.capitalize()) + self.write('<tr class="list-header"><th colspan=2 align=left>' + '<a href="%s">%s</a></th></tr>'%(cn, cn.capitalize())) for key, value in cl.properties.items(): if value is None: value = '' else: value = str(value) @@ -1012,6 +1091,8 @@ if action == 'logout': self.logout() return + + # see if we're to display an existing node m = dre.match(action) if m: self.classname = m.group(1) @@ -1030,6 +1111,8 @@ raise NotFound func() return + + # see if we're to put up the new node page m = nre.match(action) if m: self.classname = m.group(1) @@ -1039,6 +1122,8 @@ raise NotFound func() return + + # otherwise, display the named class self.classname = action try: self.db.getclass(self.classname) @@ -1202,6 +1287,10 @@ # # $Log: not supported by cvs2svn $ +# Revision 1.102 2002/02/15 07:08:44 richard +# . Alternate email addresses are now available for users. See the MIGRATION +# file for info on how to activate the feature. +# # Revision 1.101 2002/02/14 23:39:18 richard # . All forms now have "double-submit" protection when Javascript is enabled # on the client-side.
--- a/roundup/htmltemplate.py Wed Feb 20 05:04:32 2002 +0000 +++ b/roundup/htmltemplate.py Wed Feb 20 05:05:29 2002 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: htmltemplate.py,v 1.76 2002-02-16 09:10:52 richard Exp $ +# $Id: htmltemplate.py,v 1.77 2002-02-20 05:05:29 richard Exp $ __doc__ = """ Template engine. @@ -33,6 +33,9 @@ except ImportError: StructuredText = None +class MissingTemplateError(ValueError): + pass + class TemplateFunctions: def __init__(self): self.form = None @@ -714,8 +717,12 @@ # XXX deviate from spec here ... # load the index section template and figure the default columns from it - template = open(os.path.join(self.templates, - self.classname+'.index')).read() + try: + template = open(os.path.join(self.templates, + self.classname+'.index')).read() + except IOError, error: + if error.errno not in (errno.ENOENT, errno.ESRCH): raise + raise MissingTemplateError, self.classname+'.index' all_columns = self.col_re.findall(template) if not columns: columns = [] @@ -1070,6 +1077,9 @@ # # $Log: not supported by cvs2svn $ +# Revision 1.76 2002/02/16 09:10:52 richard +# oops +# # Revision 1.75 2002/02/16 08:43:23 richard # . #517906 ] Attribute order in "View customisation" #
--- a/roundup/hyperdb.py Wed Feb 20 05:04:32 2002 +0000 +++ b/roundup/hyperdb.py Wed Feb 20 05:05:29 2002 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: hyperdb.py,v 1.55 2002-02-15 07:27:12 richard Exp $ +# $Id: hyperdb.py,v 1.56 2002-02-20 05:05:28 richard Exp $ __doc__ = """ Hyperdatabase implementation, especially field types. @@ -490,6 +490,7 @@ if node.has_key(self.db.RETIRED_FLAG): raise IndexError num_re = re.compile('^\d+$') + set = {} for key, value in propvalues.items(): # check to make sure we're not duplicating an existing key if key == self.key and node[key] != value: @@ -505,6 +506,13 @@ # the writeable properties. prop = self.properties[key] + # if the value's the same as the existing value, no sense in + # doing anything + if value == node[key]: + del propvalues[key] + continue + + # do stuff based on the prop type if isinstance(prop, Link): link_class = self.properties[key].classname # if it isn't a number, it's a key @@ -598,6 +606,11 @@ node[key] = value + # nothing to do? + if not propvalues: + return + + # do the set, and journal it self.db.setnode(self.classname, nodeid, node) self.db.addjournal(self.classname, nodeid, 'set', propvalues) @@ -633,6 +646,10 @@ return self.db.getjournal(self.classname, nodeid) # Locating nodes: + def hasnode(self, nodeid): + '''Determine if the given nodeid actually exists + ''' + return self.db.hasnode(self.classname, nodeid) def setkey(self, propname): """Select a String property of this class to be the key property. @@ -1066,6 +1083,9 @@ # # $Log: not supported by cvs2svn $ +# Revision 1.55 2002/02/15 07:27:12 richard +# Oops, precedences around the way w0rng. +# # Revision 1.54 2002/02/15 07:08:44 richard # . Alternate email addresses are now available for users. See the MIGRATION # file for info on how to activate the feature.
