summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a078297)
raw | patch | inline | side by side (parent: a078297)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Wed, 20 Feb 2002 05:05:29 +0000 (05:05 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Wed, 20 Feb 2002 05:05:29 +0000 (05:05 +0000) |
- access using the admin "class list" interface
- limited to admin-only
- requires the csv module from object-craft (url given if it's missing)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@639 57a73879-2fb5-44c3-a270-3262357dd7e2
- limited to admin-only
- requires the csv module from object-craft (url given if it's missing)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@639 57a73879-2fb5-44c3-a270-3262357dd7e2
CHANGES.txt | patch | blob | history | |
roundup/cgi_client.py | patch | blob | history | |
roundup/htmltemplate.py | patch | blob | history | |
roundup/hyperdb.py | patch | blob | history |
diff --git a/CHANGES.txt b/CHANGES.txt
index f20f74d587bbab3a63c650c685398b9da936f344..646fa55d749219f75c036b0f4415762bd93075cc 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
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.
. #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
diff --git a/roundup/cgi_client.py b/roundup/cgi_client.py
index 661dbb06b9f0d153059a59127998d5b47ae52303..0e446d48c3416eba68af6f936306d1c5e1bed7cd 100644 (file)
--- a/roundup/cgi_client.py
+++ b/roundup/cgi_client.py
# 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).
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
'''
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)
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)
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)
raise NotFound
func()
return
+
+ # otherwise, display the named class
self.classname = action
try:
self.db.getclass(self.classname)
#
# $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.
index ad7d8dec93a033695389c723b7dee0da1b8920e9..92c0937e5e603aab95407b8f92399fd9ca848431 100644 (file)
--- a/roundup/htmltemplate.py
+++ b/roundup/htmltemplate.py
# 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.
except ImportError:
StructuredText = None
+class MissingTemplateError(ValueError):
+ pass
+
class TemplateFunctions:
def __init__(self):
self.form = None
# 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 = []
#
# $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"
#
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index f0aaf929637b1fdd6143266719275f5e0a780537..0386a7371fe6b154de8f2a2d928a49971de66ecc 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# 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.
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:
# 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
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)
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.
#
# $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.