Mercurial > p > roundup > code
changeset 1911:f5c804379c85
fixed ZRoundup - mostly changes to classic template
line wrap: on
line diff
--- a/CHANGES.txt Tue Nov 11 22:37:25 2003 +0000 +++ b/CHANGES.txt Wed Nov 12 01:00:59 2003 +0000 @@ -7,7 +7,8 @@ - support setgid and running on port < 1024 (sf patch 777528) - using Zope3's test runner now, allowing GC checks, nicer controls and coverage analysis -- added postgresql backend (originally from patch #761740, many changes since) +- added postgresql backend (originally from sf patch 761740, many changes + since) - all RDBMS backends now have indexes on several columns - Change nosymessage and send_message to accept msgid=None (RFE #707235). @@ -17,18 +18,19 @@ couple of cases - HTML 4.01 validation on the 'classic' backend - Messages to the mailgw can be about classes other than issues now. -- Signature matching is more precise (bug #827775). -- Anonymous user can no longer edit or view itself (bug #828901). -- Corrected typo in installation.html (bug #822967). +- Signature matching is more precise (sf bug 827775). +- Anonymous user can no longer edit or view itself (sf bug 828901). +- Corrected typo in installation.html (sf bug 822967). - Clarified listTemplates docstring. - Print a nicer error message when the address is already in use - (bug #798659). + (sf bug 798659). - Remove empty lines before sending strings off to the csv parser - (bug #821364). -- Centralised conversion of user-input data to hyperdb values (bug #802405, - bug #817217, rfe #816994) + (sf bug 821364). +- Centralised conversion of user-input data to hyperdb values (sf bug 802405, + sf bug 817217, sf rfe 816994) - recalculate SHA on template files when installed tracker used as template (sf bug 827510) +- fixed ZRoundup (sf bug 624380) Cleanup: - Replace curuserid attribute on Database with the extended getuid() method.
--- a/doc/upgrading.txt Tue Nov 11 22:37:25 2003 +0000 +++ b/doc/upgrading.txt Wed Nov 12 01:00:59 2003 +0000 @@ -21,6 +21,29 @@ might still need to create an index "create index ids_name_idx on ids(name)". +0.7.0 ZRoundup changes +---------------------- + +The templates in your tracker's html directory will need updating if you +wish to use ZRoundup. If you've not modified those files (or some of them), +you may just copy the new versions from the Roundup source in the +templates/classic/html directory. + +If you have modified the html files, then you'll need to manually edit them +to change all occurances of special form variables from using the colon ":" +special character to the at "@" special character. That is, variables such +as:: + + :action :required :template :remove:messages ... + +should become: + + @action @required @template @remove@messages ... + +Note that ``tal:`` statements are unaffected. So are TAL expression type +prefixes such as ``python:`` and ``string:``. Please ask on the +roundup-users mailing list for help if you're unsure. + Migrating from 0.6.x to 0.6.3 =============================
--- a/frontends/ZRoundup/ZRoundup.py Tue Nov 11 22:37:25 2003 +0000 +++ b/frontends/ZRoundup/ZRoundup.py Wed Nov 12 01:00:59 2003 +0000 @@ -14,7 +14,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: ZRoundup.py,v 1.16 2002-10-18 03:34:58 richard Exp $ +# $Id: ZRoundup.py,v 1.17 2003-11-12 01:00:58 richard Exp $ # ''' ZRoundup module - exposes the roundup web interface to Zope @@ -26,11 +26,6 @@ independently of Zope. The roundup code is kept in memory though, and it runs in the same server as all your other Zope stuff, so it does have _some_ advantages over regular CGI :) - -It also means that any requests which specify :filter, :columns or :sort -_must_ be done using a GET, so that this interface can re-parse the -QUERY_STRING. Zope interprets the ':' as a special character, and the special -args are lost to it. ''' import urlparse @@ -142,16 +137,7 @@ # the last element is the name env['TRACKER_NAME'] = path_components[-1] - if env['REQUEST_METHOD'] == 'GET': - # force roundup to re-parse the request because Zope fiddles - # with it and we lose all the :filter, :columns, etc goodness - form = None - else: - # For some reason, CRs are embeded in multiline notes. - # It doesn't occur with apache/roundup.cgi, though. - form = FormWrapper(self.REQUEST.form) - - print (env['SCRIPT_NAME'], env['PATH_INFO']) + form = FormWrapper(self.REQUEST.form) return instance.Client(instance, request, env, form) security.declareProtected('View', 'index_html') @@ -160,7 +146,7 @@ ''' # Redirect misdirected requests -- bugs 558867 , 565992 # PATH_INFO, as defined by the CGI spec, has the *real* request path - orig_path = self.REQUEST.environ[ 'PATH_INFO' ] + orig_path = self.REQUEST.environ['PATH_INFO'] if orig_path[-1] != '/' : url = urlparse.urlparse( self.absolute_url() ) url = list( url ) # make mutable @@ -179,31 +165,30 @@ def __getitem__(self, item): '''All other URL accesses are passed throuh to roundup ''' - return PathElement(self, item) + return PathElement(self, item).__of__(self) -class PathElement(Item, Implicit, Persistent): - def __init__(self, parent, path): - self.parent = parent +class PathElement(Item, Implicit): + def __init__(self, zr, path): + self.zr = zr self.path = path def __getitem__(self, item): ''' Get a subitem. ''' - return PathElement(self.path + '/' + item) + return PathElement(self.zr, self.path + '/' + item).__of__(self) - def __call__(self, *args, **kw): + def index_html(self, REQUEST=None): ''' Actually call through to roundup to handle the request. ''' - print '*****', self.path try: - client = self.parent.roundup_opendb() + client = self.zr.roundup_opendb() # fake the path that roundup should use client.path = self.path # and call roundup to do something client.main() return '' except NotFound: - raise 'NotFound', self.REQUEST.URL + raise 'NotFound', REQUEST.URL pass except: import traceback
--- a/roundup/backends/back_mysql.py Tue Nov 11 22:37:25 2003 +0000 +++ b/roundup/backends/back_mysql.py Wed Nov 12 01:00:59 2003 +0000 @@ -53,7 +53,7 @@ mysql_backend = 'InnoDB' #mysql_backend = 'BDB' # much slower, only use if you have no choice - def open_connection(self): + def sql_open_connection(self): db = getattr(self.config, 'MYSQL_DATABASE') try: self.conn = MySQLdb.connect(*db) @@ -81,9 +81,6 @@ self.mysql_backend) self.sql("CREATE INDEX ids_name_idx on ids(name)") - def close(self): - self.conn.close() - def __repr__(self): return '<myroundsql 0x%x>'%id(self)
--- a/roundup/backends/back_postgresql.py Tue Nov 11 22:37:25 2003 +0000 +++ b/roundup/backends/back_postgresql.py Wed Nov 12 01:00:59 2003 +0000 @@ -8,15 +8,15 @@ # psycopg backend for roundup # -from roundup.backends.rdbms_common import * +from roundup import hyperdb, date from roundup.backends import rdbms_common import psycopg import os, shutil, popen2 -class Database(Database): +class Database(rdbms_common.Database): arg = '%s' - def open_connection(self): + def sql_open_connection(self): db = getattr(self.config, 'POSTGRESQL_DATABASE') try: self.conn = psycopg.connect(**db) @@ -33,18 +33,9 @@ self.sql("CREATE TABLE schema (schema TEXT)") self.sql("CREATE TABLE ids (name VARCHAR(255), num INT4)") - def close(self): - self.conn.close() - def __repr__(self): return '<roundpsycopgsql 0x%x>' % id(self) - def sql_fetchone(self): - return self.cursor.fetchone() - - def sql_fetchall(self): - return self.cursor.fetchall() - def sql_stringquote(self, value): ''' psycopg.QuotedString returns a "buffer" object with the single-quotes around it... ''' @@ -56,44 +47,6 @@ self.cursor.execute(sql, (table_name, index_name)) return self.cursor.fetchone()[0] - def save_dbschema(self, schema): - s = repr(self.database_schema) - self.sql('INSERT INTO schema VALUES (%s)', (s,)) - - def load_dbschema(self): - self.cursor.execute('SELECT schema FROM schema') - schema = self.cursor.fetchone() - if schema: - return eval(schema[0]) - - def save_journal(self, classname, cols, nodeid, journaldate, - journaltag, action, params): - params = repr(params) - entry = (nodeid, journaldate, journaltag, action, params) - - a = self.arg - sql = 'INSERT INTO %s__journal (%s) values (%s, %s, %s, %s, %s)'%( - classname, cols, a, a, a, a, a) - - if __debug__: - print >>hyperdb.DEBUG, 'addjournal', (self, sql, entry) - - self.cursor.execute(sql, entry) - - def load_journal(self, classname, cols, nodeid): - sql = 'SELECT %s FROM %s__journal WHERE nodeid = %s' % ( - cols, classname, self.arg) - - if __debug__: - print >>hyperdb.DEBUG, 'getjournal', (self, sql, nodeid) - - self.cursor.execute(sql, (nodeid,)) - res = [] - for nodeid, date_stamp, user, action, params in self.cursor.fetchall(): - params = eval(params) - res.append((nodeid, date.Date(date_stamp), user, action, params)) - return res - def create_class_table(self, spec): cols, mls = self.determine_columns(spec.properties.items()) cols.append('id') @@ -126,79 +79,10 @@ self.cursor.execute(sql) -class PsycopgClass: - def find(self, **propspec): - """Get the ids of nodes in this class which link to the given nodes.""" - - 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 - l = [] - where = [] - allvalues = () - a = self.db.arg - for prop, values in propspec: - if not isinstance(props[prop], hyperdb.Link): - continue - 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: - self.db.sql('SELECT id AS nodeid FROM _%s WHERE %s' % ( - self.classname, ' and '.join(where)), allvalues) - l += [x[0] for x in self.db.sql_fetchall()] - - # now multilinks - for prop, values in propspec: - vals = () - if not isinstance(props[prop], hyperdb.Multilink): - continue - if type(values) is type(''): - vals = (values,) - s = a - else: - vals = tuple(values.keys()) - s = ','.join([a]*len(values)) - query = 'SELECT nodeid FROM %s_%s WHERE linkid IN (%s)'%( - self.classname, prop, s) - self.db.sql(query, vals) - l += [x[0] for x in self.db.sql_fetchall()] - - if __debug__: - print >>hyperdb.DEBUG, 'find ... ', l - - # Remove duplicated ids - d = {} - for k in l: - d[k] = 1 - return d.keys() - - return l - -class Class(PsycopgClass, rdbms_common.Class): +class Class(rdbms_common.Class): pass -class IssueClass(PsycopgClass, rdbms_common.IssueClass): +class IssueClass(rdbms_common.IssueClass): pass -class FileClass(PsycopgClass, rdbms_common.FileClass): +class FileClass(rdbms_common.FileClass): pass
--- a/roundup/backends/back_sqlite.py Tue Nov 11 22:37:25 2003 +0000 +++ b/roundup/backends/back_sqlite.py Wed Nov 12 01:00:59 2003 +0000 @@ -1,17 +1,19 @@ -# $Id: back_sqlite.py,v 1.11 2003-11-11 11:19:18 richard Exp $ +# $Id: back_sqlite.py,v 1.12 2003-11-12 01:00:58 richard Exp $ __doc__ = ''' See https://pysqlite.sourceforge.net/ for pysqlite info ''' -import base64, marshal -from roundup.backends.rdbms_common import * +import os, base64, marshal + +from roundup import hyperdb +from roundup.backends import rdbms_common from roundup.backends import locking import sqlite -class Database(Database): +class Database(rdbms_common.Database): # char to use for positional arguments arg = '%s' - def open_connection(self): + def sql_open_connection(self): # ensure files are group readable and writable os.umask(0002) db = os.path.join(self.config.DATABASE, 'db') @@ -34,10 +36,8 @@ self.cursor.execute('create table ids (name varchar, num integer)') self.cursor.execute('create index ids_name_idx on ids(name)') - def close(self): - ''' Close off the connection. - - Squash any error caused by us already having closed the + def sql_close(self): + ''' Squash any error caused by us already having closed the connection. ''' try: @@ -46,55 +46,19 @@ if str(value) != 'close failed - Connection is closed.': raise - # release the lock too - if self.lockfile is not None: - locking.release_lock(self.lockfile) - if self.lockfile is not None: - self.lockfile.close() - self.lockfile = None - - def rollback(self): - ''' Reverse all actions from the current transaction. - - Undo all the changes made since the database was opened or the - last commit() or rollback() was performed. - - Squash any error caused by us having closed the connection (and + def sql_rollback(self): + ''' Squash any error caused by us having closed the connection (and therefore not having anything to roll back) ''' - if __debug__: - print >>hyperdb.DEBUG, 'rollback', (self,) - - # roll back try: self.conn.rollback() except sqlite.ProgrammingError, value: if str(value) != 'rollback failed - Connection is closed.': raise - # roll back "other" transaction stuff - for method, args in self.transactions: - # delete temporary files - if method == self.doStoreFile: - self.rollbackStoreFile(*args) - self.transactions = [] - - # clear the cache - self.clearCache() - def __repr__(self): return '<roundlite 0x%x>'%id(self) - def sql_fetchone(self): - ''' Fetch a single row. If there's nothing to fetch, return None. - ''' - return self.cursor.fetchone() - - def sql_fetchall(self): - ''' Fetch a single row. If there's nothing to fetch, return []. - ''' - return self.cursor.fetchall() - def sql_commit(self): ''' Actually commit to the database. @@ -113,86 +77,22 @@ return 1 return 0 - def save_dbschema(self, schema): - ''' Save the schema definition that the database currently implements - ''' - s = repr(self.database_schema) - self.sql('insert into schema values (%s)', (s,)) - - def load_dbschema(self): - ''' Load the schema definition that the database currently implements - ''' - self.cursor.execute('select schema from schema') - return eval(self.cursor.fetchone()[0]) - - def save_journal(self, classname, cols, nodeid, journaldate, - journaltag, action, params): - ''' Save the journal entry to the database - ''' - # make the params db-friendly - params = repr(params) - entry = (nodeid, journaldate, journaltag, action, params) - - # do the insert - a = self.arg - sql = 'insert into %s__journal (%s) values (%s,%s,%s,%s,%s)'%(classname, - cols, a, a, a, a, a) - if __debug__: - print >>hyperdb.DEBUG, 'addjournal', (self, sql, entry) - self.cursor.execute(sql, entry) - - def load_journal(self, classname, cols, nodeid): - ''' Load the journal from the database +class sqliteClass: + def filter(self, search_matches, filterspec, sort=(None,None), + group=(None,None)): + ''' If there's NO matches to a fetch, sqlite returns NULL + instead of nothing ''' - # now get the journal entries - sql = 'select %s from %s__journal where nodeid=%s'%(cols, classname, - self.arg) - if __debug__: - print >>hyperdb.DEBUG, 'getjournal', (self, sql, nodeid) - self.cursor.execute(sql, (nodeid,)) - res = [] - for nodeid, date_stamp, user, action, params in self.cursor.fetchall(): - params = eval(params) - res.append((nodeid, date.Date(date_stamp), user, action, params)) - return res + return filter(None, rdbms_common.Class.filter(self, search_matches, + filterspec, sort=sort, group=group)) - def unserialise(self, classname, node): - ''' Decode the marshalled node data +class Class(sqliteClass, rdbms_common.Class): + pass - SQLite stringifies _everything_... so we need to re-numberificate - Booleans and Numbers. - ''' - if __debug__: - print >>hyperdb.DEBUG, 'unserialise', classname, node - properties = self.getclass(classname).getprops() - d = {} - for k, v in node.items(): - # if the property doesn't exist, or is the "retired" flag then - # it won't be in the properties dict - if not properties.has_key(k): - d[k] = v - continue - - # get the property spec - prop = properties[k] +class IssueClass(sqliteClass, rdbms_common.IssueClass): + pass - if isinstance(prop, Date) and v is not None: - d[k] = date.Date(v) - elif isinstance(prop, Interval) and v is not None: - d[k] = date.Interval(v) - elif isinstance(prop, Password) and v is not None: - p = password.Password() - p.unpack(v) - d[k] = p - elif isinstance(prop, Boolean) and v is not None: - d[k] = int(v) - elif isinstance(prop, Number) and v is not None: - # try int first, then assume it's a float - try: - d[k] = int(v) - except ValueError: - d[k] = float(v) - else: - d[k] = v - return d +class FileClass(sqliteClass, rdbms_common.FileClass): + pass +
--- a/roundup/backends/rdbms_common.py Tue Nov 11 22:37:25 2003 +0000 +++ b/roundup/backends/rdbms_common.py Wed Nov 12 01:00:59 2003 +0000 @@ -1,4 +1,4 @@ -# $Id: rdbms_common.py,v 1.67 2003-11-11 11:19:18 richard Exp $ +# $Id: rdbms_common.py,v 1.68 2003-11-12 01:00:58 richard Exp $ ''' Relational database (SQL) backend common code. Basics: @@ -69,13 +69,13 @@ self.lockfile = None # open a connection to the database, creating the "conn" attribute - self.open_connection() + self.sql_open_connection() def clearCache(self): self.cache = {} self.cache_lru = [] - def open_connection(self): + def sql_open_connection(self): ''' Open a connection to the database, creating it if necessary ''' raise NotImplemented @@ -93,7 +93,12 @@ def sql_fetchone(self): ''' Fetch a single row. If there's nothing to fetch, return None. ''' - raise NotImplemented + return self.cursor.fetchone() + + def sql_fetchall(self): + ''' Fetch all rows. If there's nothing to fetch, return []. + ''' + return self.cursor.fetchall() def sql_stringquote(self, value): ''' Quote the string so it's safe to put in the 'sql quotes' @@ -103,12 +108,14 @@ def save_dbschema(self, schema): ''' Save the schema definition that the database currently implements ''' - raise NotImplemented + s = repr(self.database_schema) + self.sql('insert into schema values (%s)', (s,)) def load_dbschema(self): ''' Load the schema definition that the database currently implements ''' - raise NotImplemented + self.cursor.execute('select schema from schema') + return eval(self.cursor.fetchone()[0]) def post_init(self): ''' Called once the schema initialisation has finished. @@ -806,8 +813,14 @@ p = password.Password() p.unpack(v) d[k] = p - elif (isinstance(prop, Boolean) or isinstance(prop, Number)) and v is not None: - d[k]=float(v) + elif isinstance(prop, Boolean) and v is not None: + d[k] = int(v) + elif isinstance(prop, Number) and v is not None: + # try int first, then assume it's a float + try: + d[k] = int(v) + except ValueError: + d[k] = float(v) else: d[k] = v return d @@ -865,12 +878,6 @@ self.save_journal(classname, cols, nodeid, journaldate, journaltag, action, params) - def save_journal(self, classname, cols, nodeid, journaldate, - journaltag, action, params): - ''' Save the journal entry to the database - ''' - raise NotImplemented - def getjournal(self, classname, nodeid): ''' get the journal for id ''' @@ -881,10 +888,36 @@ cols = ','.join('nodeid date tag action params'.split()) return self.load_journal(classname, cols, nodeid) + def save_journal(self, classname, cols, nodeid, journaldate, + journaltag, action, params): + ''' Save the journal entry to the database + ''' + # make the params db-friendly + params = repr(params) + entry = (nodeid, journaldate, journaltag, action, params) + + # do the insert + a = self.arg + sql = 'insert into %s__journal (%s) values (%s,%s,%s,%s,%s)'%(classname, + cols, a, a, a, a, a) + if __debug__: + print >>hyperdb.DEBUG, 'addjournal', (self, sql, entry) + self.cursor.execute(sql, entry) + def load_journal(self, classname, cols, nodeid): ''' Load the journal from the database ''' - raise NotImplemented + # now get the journal entries + sql = 'select %s from %s__journal where nodeid=%s'%(cols, classname, + self.arg) + if __debug__: + print >>hyperdb.DEBUG, 'load_journal', (self, sql, nodeid) + self.cursor.execute(sql, (nodeid,)) + res = [] + for nodeid, date_stamp, user, action, params in self.cursor.fetchall(): + params = eval(params) + res.append((nodeid, date.Date(date_stamp), user, action, params)) + return res def pack(self, pack_before): ''' Delete all journal entries except "create" before 'pack_before'. @@ -933,6 +966,9 @@ # clear out the transactions self.transactions = [] + def sql_rollback(self): + self.conn.rollback() + def rollback(self): ''' Reverse all actions from the current transaction. @@ -942,8 +978,7 @@ if __debug__: print >>hyperdb.DEBUG, 'rollback', (self,) - # roll back - self.conn.rollback() + self.sql_rollback() # roll back "other" transaction stuff for method, args in self.transactions: @@ -961,10 +996,13 @@ # return the classname, nodeid so we reindex this content return (classname, nodeid) + def sql_close(self): + self.conn.close() + def close(self): ''' Close off the connection. ''' - self.conn.close() + self.sql_close() if self.lockfile is not None: locking.release_lock(self.lockfile) if self.lockfile is not None: @@ -2061,12 +2099,10 @@ else: # psycopg doesn't like empty args self.db.cursor.execute(sql) - l = self.db.cursor.fetchall() + l = self.db.sql_fetchall() # return the IDs (the first column) - # XXX The filter(None, l) bit is sqlite-specific... if there's _NO_ - # XXX matches to a fetch, it returns NULL instead of nothing!?! - return filter(None, [row[0] for row in l]) + return [row[0] for row in l] def count(self): '''Get the number of nodes in this class.
--- a/roundup/cgi/client.py Tue Nov 11 22:37:25 2003 +0000 +++ b/roundup/cgi/client.py Wed Nov 12 01:00:59 2003 +0000 @@ -1,4 +1,4 @@ -# $Id: client.py,v 1.144 2003-11-11 00:35:14 richard Exp $ +# $Id: client.py,v 1.145 2003-11-12 01:00:59 richard Exp $ __doc__ = """ WWW request handler (also used in the stand-alone server). @@ -422,7 +422,7 @@ else: self.template = '' return - elif path[0] == '_file': + elif path[0] in ('_file', '@@file'): raise SendStaticFile, os.path.join(*path[1:]) else: self.classname = path[0]
--- a/roundup/cgi/templating.py Tue Nov 11 22:37:25 2003 +0000 +++ b/roundup/cgi/templating.py Wed Nov 12 01:00:59 2003 +0000 @@ -469,14 +469,14 @@ if property: property = '&property=%s'%property return '<a class="classhelp" href="javascript:help_window(\'%s?'\ - ':startwith=0&:template=help&properties=%s%s\', \'%s\', \ + '@startwith=0&@template=help&properties=%s%s\', \'%s\', \ \'%s\')">%s</a>'%(self.classname, properties, property, width, height, label) def submit(self, label="Submit New Entry"): ''' Generate a submit button (and action hidden element) ''' - return ' <input type="hidden" name=":action" value="new">\n'\ + return ' <input type="hidden" name="@action" value="new">\n'\ ' <input type="submit" name="submit" value="%s">'%label def history(self): @@ -554,7 +554,7 @@ def submit(self, label="Submit Changes"): ''' Generate a submit button (and action hidden element) ''' - return ' <input type="hidden" name=":action" value="edit">\n'\ + return ' <input type="hidden" name="@action" value="edit">\n'\ ' <input type="submit" name="submit" value="%s">'%label def journal(self, direction='descending'): @@ -773,7 +773,7 @@ req.classname = self._klass.get(self._nodeid, 'klass') name = self._klass.get(self._nodeid, 'name') req.updateFromURL(self._klass.get(self._nodeid, 'url') + - '&:queryname=%s'%urllib.quote(name)) + '&@queryname=%s'%urllib.quote(name)) # new template, using the specified classname and request pt = Templates(self._db.config.TEMPLATES).get(req.classname, 'search') @@ -961,9 +961,9 @@ def confirm(self, size = 30): ''' Render a second form edit field for the property, used for confirmation that the user typed the password correctly. Generates - a field with name ":confirm:name". + a field with name "@confirm@name". ''' - return '<input type="password" name=":confirm:%s" size="%s">'%( + return '<input type="password" name="@confirm@%s" size="%s">'%( self._formname, size) class NumberHTMLProperty(HTMLProperty):
--- a/templates/classic/html/_generic.help.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/_generic.help.html Wed Nov 12 01:00:59 2003 +0000 @@ -1,7 +1,7 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html> <head> - <link rel="stylesheet" type="text/css" href="_file/style.css" /> + <link rel="stylesheet" type="text/css" href="@@file/style.css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" /> <tal:block tal:condition="python:request.form.has_key('property')"> <title tal:content="string:${request/form/property/value} help">Property</title> @@ -10,13 +10,13 @@ // this is the name of the field in the original form that we're working on field = '${request/form/property/value}';" > </script> - <script src="_file/help_controls.js" type="text/javascript"><!-- + <script src="@@file/help_controls.js" type="text/javascript"><!-- //--></script> </tal:block> </head> <body class="body" onload="resetList();"> <form name="frm_help" tal:attributes="action request/base" - tal:define="start python:int(request.form[':startwith'].value); + tal:define="start python:int(request.form['@startwith'].value); batch python:utils.Batch(context.list(), 500, start); props python:request.form['properties'].value.split(',')"> @@ -60,14 +60,14 @@ <tr class="navigation"> <th> <a tal:define="prev batch/previous" tal:condition="prev" - tal:attributes="href string:${request/classname}?:template=help&:startwith=${prev/first}&properties=${request/form/properties/value}"><< previous</a> + tal:attributes="href string:${request/classname}?@template=help&@startwith=${prev/first}&properties=${request/form/properties/value}"><< previous</a> </th> <th tal:content="python: '%d...%d out of %d'%(batch.start, batch.start+batch.length-1, batch.sequence_length)">current</th> <th> <a tal:define="next batch/next" tal:condition="next" - tal:attributes="href string:${request/classname}?:template=help&:startwith=${next/first}&properties=${request/form/properties/value}">next >></a> + tal:attributes="href string:${request/classname}?@template=help&@startwith=${next/first}&properties=${request/form/properties/value}">next >></a> </th> </tr>
--- a/templates/classic/html/_generic.index.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/_generic.index.html Wed Nov 12 01:00:59 2003 +0000 @@ -35,7 +35,7 @@ tal:attributes="action context/designator"> <textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea> <br> -<input type="hidden" name=":action" value="editCSV"> +<input type="hidden" name="@action" value="editCSV"> <input type="submit" value="Edit Items"> </form> </tal:block>
--- a/templates/classic/html/_generic.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/_generic.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -14,8 +14,7 @@ enctype="multipart/form-data" tal:condition="context/is_edit_ok" tal:attributes="action context/designator"> -<input type="hidden" name=":template" value="item"> -<input type="hidden" name=":required" value="title"> +<input type="hidden" name="@template" value="item"> <table class="form">
--- a/templates/classic/html/file.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/file.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -27,11 +27,11 @@ <tr> <td> - <input type="hidden" name=":template" value="item"> - <input type="hidden" name=":required" value="name,type"> - <input type="hidden" name=":multilink" - tal:condition="python:request.form.has_key(':multilink')" - tal:attributes="value request/form/:multilink/value"> + <input type="hidden" name="@template" value="item"> + <input type="hidden" name="@required" value="name,type"> + <input type="hidden" name="@multilink" + tal:condition="python:request.form.has_key('@multilink')" + tal:attributes="value request/form/@multilink/value"> </td> <td tal:content="structure context/submit">submit button here</td> </tr>
--- a/templates/classic/html/issue.index.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/issue.index.html Wed Nov 12 01:00:59 2003 +0000 @@ -64,7 +64,7 @@ <th> <a tal:define="prev batch/previous" tal:condition="prev" tal:attributes="href python:request.indexargs_href(request.classname, - {':startwith':prev.first, ':pagesize':prev.size})"><< previous</a> + {'@startwith':prev.first, '@pagesize':prev.size})"><< previous</a> </th> <th tal:content="python: '%d...%d out of %d'%(batch.start, @@ -72,7 +72,7 @@ <th> <a tal:define="next batch/next" tal:condition="next" tal:attributes="href python:request.indexargs_href(request.classname, - {':startwith':next.first, ':pagesize':next.size})">next >></a> + {'@startwith':next.first, '@pagesize':next.size})">next >></a> </th> </tr> @@ -87,7 +87,7 @@ <tr tal:condition="batch"> <th>Sort on:</th> <td> - <select name=":sort"> + <select name="@sort"> <option value="">- nothing -</option> <option tal:repeat="col context/properties" tal:attributes="value col/_name; @@ -96,14 +96,14 @@ </select> </td> <th>Descending:</th> - <td><input type="checkbox" name=":sortdir" + <td><input type="checkbox" name="@sortdir" tal:attributes="checked python:request.sort[0] == '-'"> </td> </tr> <tr> <th>Group on:</th> <td> - <select name=":group"> + <select name="@group"> <option value="">- nothing -</option> <option tal:repeat="col context/properties" tal:attributes="value col/_name; @@ -112,7 +112,7 @@ </select> </td> <th>Descending:</th> - <td><input type="checkbox" name=":groupdir" + <td><input type="checkbox" name="@groupdir" tal:attributes="checked python:request.group[0] == '-'"> </td> </tr> @@ -128,4 +128,3 @@ </td> </tal:block> -
--- a/templates/classic/html/issue.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/issue.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -67,21 +67,21 @@ <tr> <th>Change Note</th> <td colspan=3> - <textarea tal:content="request/form/:note/value | default" - name=":note" wrap="hard" rows="5" cols="80"></textarea> + <textarea tal:content="request/form/@note/value | default" + name="@note" wrap="hard" rows="5" cols="80"></textarea> </td> </tr> <tr> <th>File</th> - <td colspan=3><input type="file" name=":file" size="40"></td> + <td colspan=3><input type="file" name="@file" size="40"></td> </tr> <tr> <td> - <input type="hidden" name=":template" value="item"> - <input type="hidden" name=":required" value="title,priority"> + <input type="hidden" name="@template" value="item"> + <input type="hidden" name="@required" value="title,priority"> </td> <td colspan=3 tal:content="structure context/submit"> submit button will go here @@ -142,7 +142,7 @@ <th tal:content="string:Date: ${msg/date}">date</th> <th> <a tal:condition="context/is_edit_ok" - tal:attributes="href string:issue${context/id}?:remove:messages=${msg/id}&:action=edit">remove</a> + tal:attributes="href string:issue${context/id}?@remove@messages=${msg/id}&@action=edit">remove</a> </th> </tr> <tr>
--- a/templates/classic/html/issue.search.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/issue.search.html Wed Nov 12 01:00:59 2003 +0000 @@ -26,7 +26,7 @@ <th class="header">Group on</th> </tr> -<tr tal:define="name string::search_text"> +<tr tal:define="name string:@search_text"> <th>All text*:</th> <td metal:use-macro="search_input"></td> <td> </td> @@ -136,40 +136,40 @@ <tr> <th>Pagesize:</th> -<td><input name=":pagesize" size="3" value="50" - tal:attributes="value request/form/:pagesize/value | default"></td> +<td><input name="@pagesize" size="3" value="50" + tal:attributes="value request/form/@pagesize/value | default"></td> </tr> <tr> <th>Start With:</th> -<td><input name=":startwith" size="3" value="0" - tal:attributes="value request/form/:startwith/value | default"></td> +<td><input name="@startwith" size="3" value="0" + tal:attributes="value request/form/@startwith/value | default"></td> </tr> <tr> <th>Sort Descending:</th> -<td><input type="checkbox" name=":sortdir" +<td><input type="checkbox" name="@sortdir" tal:attributes="checked python:request.sort[0] == '-' or request.sort[0] is None"> </td> </tr> <tr> <th>Group Descending:</th> -<td><input type="checkbox" name=":groupdir" +<td><input type="checkbox" name="@groupdir" tal:attributes="checked python:request.group[0] == '-'"> </td> </tr> <tr> <th>Query name**:</th> -<td><input name=":queryname" - tal:attributes="value request/form/:queryname/value | default"></td> +<td><input name="@queryname" + tal:attributes="value request/form/@queryname/value | default"></td> </tr> <tr> <td> - <input type="hidden" name=":action" value="search"> + <input type="hidden" name="@action" value="search"> </td> <td><input type="submit" value="Search"></td> </tr>
--- a/templates/classic/html/keyword.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/keyword.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -41,8 +41,8 @@ <tr> <td> - <input type="hidden" name=":required" value="name"> - <input type="hidden" name=":template" value="item"> + <input type="hidden" name="@required" value="name"> + <input type="hidden" name="@template" value="item"> </td> <td colspan=3 tal:content="structure context/submit"> submit button will go here
--- a/templates/classic/html/page.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/page.html Wed Nov 12 01:00:59 2003 +0000 @@ -6,7 +6,7 @@ <title metal:define-slot="head_title">title goes here</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8;"> -<link rel="stylesheet" type="text/css" href="_file/style.css"> +<link rel="stylesheet" type="text/css" href="@@file/style.css"> <script tal:replace="structure request/base_javascript"> </script> @@ -36,13 +36,13 @@ tal:condition="python:request.user.hasPermission('View', 'issue')"> <b>Issues</b><br> <a tal:condition="python:request.user.hasPermission('Edit', 'issue')" - href="issue?:template=item">Create New<br></a> - <a href="issue?:sort=-activity&:group=priority&:filter=status,assignedto&:columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=-1">Show Unassigned</a><br> - <a href="issue?:sort=-activity&:group=priority&:filter=status&:columns=id,activity,title,creator,assignedto,status&status=-1,1,2,3,4,5,6,7">Show All</a><br> - <a href="issue?:template=search">Search</a><br> - <input type="submit" style="padding: 0" value="Show issue:"><input size="4" type="text" name=":number"> - <input type="hidden" name=":type" value="issue"> - <input type="hidden" name=":action" value="show"> + href="issue?@template=item">Create New<br></a> + <a href="issue?@sort=-activity&@group=priority&@filter=status,assignedto&@columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=-1">Show Unassigned</a><br> + <a href="issue?@sort=-activity&@group=priority&@filter=status&@columns=id,activity,title,creator,assignedto,status&status=-1,1,2,3,4,5,6,7">Show All</a><br> + <a href="issue?@template=search">Search</a><br> + <input type="submit" style="padding: 0" value="Show issue:"><input size="4" type="text" name="@number"> + <input type="hidden" name="@type" value="issue"> + <input type="hidden" name="@action" value="show"> </p> </form> @@ -50,23 +50,23 @@ tal:condition="python:request.user.hasPermission('View', 'keyword')"> <b>Keywords</b><br> <a tal:condition="python:request.user.hasPermission('Edit', 'keyword')" - href="keyword?:template=item">Create New<br></a> + href="keyword?@template=item">Create New<br></a> <a tal:condition="python:request.user.hasPermission('Edit', 'keyword') and len(db.keyword.list())" - href="keyword?:template=item">Edit Existing<br></a> + href="keyword?@template=item">Edit Existing<br></a> </p> <p class="classblock" tal:condition="python:request.user.username != 'anonymous'"> <b>Administration</b><br> <tal:block tal:condition="python:request.user.hasPermission('Edit', None)"> - <a href="home?:template=classlist">Class List</a><br> + <a href="home?@template=classlist">Class List</a><br> </tal:block> <a tal:condition="python:request.user.hasPermission('View', 'user') or request.user.hasPermission('Edit', 'user')" href="user" >User List</a><br> <a tal:condition="python:request.user.hasPermission('Edit', 'user')" - href="user?:template=item">Add User</a> + href="user?@template=item">Add User</a> </p> <form method="POST" tal:condition="python:request.user.username=='anonymous'" @@ -75,20 +75,20 @@ <b>Login</b><br> <input size="10" name="__login_name"><br> <input size="10" type="password" name="__login_password"><br> - <input type="submit" name=":action" value="Login"><br> + <input type="submit" name="@action" value="Login"><br> <span tal:replace="structure request/indexargs_form" /> - <a href="user?:template=register" + <a href="user?@template=register" tal:condition="python:request.user.hasPermission('Web Registration')">Register<br></a> - <a href="user?:template=forgotten">Lost your login?</a><br> + <a href="user?@template=forgotten">Lost your login?</a><br> </p> </form> <p class="userblock" tal:condition="python:request.user.username != 'anonymous'"> <b>Hello,</b> <b tal:content="request/user/username">username</b><br> - <a tal:attributes="href string:issue?:sort=-activity&:group=priority&:filter=status,assignedto&:columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=${request/user/id}">My Issues</a><br> + <a tal:attributes="href string:issue?@sort=-activity&@group=priority&@filter=status,assignedto&@columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=${request/user/id}">My Issues</a><br> <a tal:attributes="href string:user${request/user/id}">My Details</a><br> <a tal:attributes="href python:request.indexargs_href('', - {':action':'logout'})">Logout</a> + {'@action':'logout'})">Logout</a> </p> <p class="userblock"> <b>Help</b><br> @@ -133,19 +133,19 @@ </td> <td metal:define-macro="column_input"> - <input type="checkbox" name=":columns" + <input type="checkbox" name="@columns" tal:attributes="value name; checked python:name in cols"> </td> <td metal:define-macro="sort_input"> - <input type="radio" name=":sort" + <input type="radio" name="@sort" tal:attributes="value name; checked python:name == sort_on"> </td> <td metal:define-macro="group_input"> - <input type="radio" name=":group" + <input type="radio" name="@group" tal:attributes="value name; checked python:name == group_on"> </td>
--- a/templates/classic/html/user.index.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/user.index.html Wed Nov 12 01:00:59 2003 +0000 @@ -30,7 +30,7 @@ <td tal:content="python:user.address.email() or default"> </td> <td tal:content="python:user.phone.plain() or default"> </td> <td tal:condition="context/is_edit_ok"> - <a tal:attributes="href string:user${user/id}?:action=retire&:template=index"> + <a tal:attributes="href string:user${user/id}?@action=retire&@template=index"> retire</a> </td> </tr>
--- a/templates/classic/html/user.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/user.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -72,8 +72,8 @@ <tr> <td> - <input type="hidden" name=":template" value="item"> - <input type="hidden" name=":required" value="username,address"> + <input type="hidden" name="@template" value="item"> + <input type="hidden" name="@required" value="username,address"> </td> <td tal:content="structure context/submit">submit button here</td> </tr> @@ -90,7 +90,7 @@ <a tal:attributes="href string:${query/klass}?${query/url}">display</a> </td> <td> - <a tal:attributes="href string:?:remove:queries=${query/id}&:action=edit">remove</a> + <a tal:attributes="href string:?@remove@queries=${query/id}&@action=edit">remove</a> </td> </tr> </table>
--- a/templates/classic/html/user.register.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/user.register.html Wed Nov 12 01:00:59 2003 +0000 @@ -64,9 +64,9 @@ <tr> <td> </td> <td> - <input type="hidden" name=":template" value="register"> - <input type="hidden" name=":required" value="username,password,address"> - <input type="hidden" name=":action" value="register"> + <input type="hidden" name="@template" value="register"> + <input type="hidden" name="@required" value="username,password,address"> + <input type="hidden" name="@action" value="register"> <input type="submit" name="submit" value="Register"> </td> </tr>
--- a/templates/classic/html/user.rego_progress.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/classic/html/user.rego_progress.html Wed Nov 12 01:00:59 2003 +0000 @@ -13,4 +13,3 @@ </td> </tal:block> -
--- a/templates/minimal/html/_generic.help.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/minimal/html/_generic.help.html Wed Nov 12 01:00:59 2003 +0000 @@ -16,7 +16,7 @@ </head> <body class="body" marginwidth="0" marginheight="0" onload="resetList();"> <form name="frm_help" action="" - tal:define="start python:int(request.form[':startwith'].value); + tal:define="start python:int(request.form['@startwith'].value); batch python:utils.Batch(context.list(), 500, start); props python:request.form['properties'].value.split(',')"> @@ -59,14 +59,14 @@ <tr class="navigation"> <th> <a tal:define="prev batch/previous" tal:condition="prev" - tal:attributes="href string:${request/classname}?:template=help&:startwith=${prev/first}&properties=${request/form/properties/value}"><< previous</a> + tal:attributes="href string:${request/classname}?@template=help&@startwith=${prev/first}&properties=${request/form/properties/value}"><< previous</a> </th> <th tal:content="python: '%d...%d out of %d'%(batch.start, batch.start+batch.length-1, batch.sequence_length)">current</th> <th> <a tal:define="next batch/next" tal:condition="next" - tal:attributes="href string:${request/classname}?:template=help&:startwith=${next/first}&properties=${request/form/properties/value}">next >></a> + tal:attributes="href string:${request/classname}?@template=help&@startwith=${next/first}&properties=${request/form/properties/value}">next >></a> </th> </tr>
--- a/templates/minimal/html/_generic.index.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/minimal/html/_generic.index.html Wed Nov 12 01:00:59 2003 +0000 @@ -34,7 +34,7 @@ <form onSubmit="return submit_once()" method="POST"> <textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea> <br> -<input type="hidden" name=":action" value="editCSV"> +<input type="hidden" name="@action" value="editCSV"> <input type="submit" value="Edit Items"> </form> </tal:block>
--- a/templates/minimal/html/_generic.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/minimal/html/_generic.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -13,8 +13,7 @@ <form method="POST" onSubmit="return submit_once()" enctype="multipart/form-data" tal:condition="context/is_edit_ok"> -<input type="hidden" name=":template" value="item"> -<input type="hidden" name=":required" value="title"> +<input type="hidden" name="@template" value="item"> <table class="form">
--- a/templates/minimal/html/page.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/minimal/html/page.html Wed Nov 12 01:00:59 2003 +0000 @@ -6,7 +6,7 @@ <title metal:define-slot="head_title">title goes here</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8;"> -<link rel="stylesheet" type="text/css" href="_file/style.css"> +<link rel="stylesheet" type="text/css" href="@@file/style.css"> <script tal:replace="structure request/base_javascript"> </script> @@ -27,30 +27,30 @@ <form method="POST" action=""> <input size="10" name="__login_name"><br> <input size="10" type="password" name="__login_password"><br> - <input type="submit" name=":action" value="login"> + <input type="submit" name="@action" value="login"> <span tal:replace="structure request/indexargs_form" /> </form> <a tal:condition="python:request.user.hasPermission('Web Registration')" - href="user?:template=register">Register</a> + href="user?@template=register">Register</a> </p> <p class="userblock" tal:condition="python:request.user.username != 'anonymous'"> <b>Hello,</b><br><b tal:content="request/user/username">username</b><br> <a tal:attributes="href string:user${request/user/id}">My Details</a><br> <a tal:attributes="href python:request.indexargs_href('', - {':action':'logout'})">Logout</a> + {'@action':'logout'})">Logout</a> </p> <p class="classblock" tal:condition="python:request.user.username != 'anonymous'"> <b>Administration</b><br> <a tal:condition="python:request.user.hasPermission('Edit', None)" - href="home?:template=classlist">Class List</a><br> + href="home?@template=classlist">Class List</a><br> <a tal:condition="python:request.user.hasPermission('View', 'user') or request.user.hasPermission('Edit', 'user')" href="user" >User List</a><br> <a tal:condition="python:request.user.hasPermission('Edit', 'user')" - href="user?:template=item">Add User</a> + href="user?@template=item">Add User</a> </p> </td> <td>
--- a/templates/minimal/html/user.item.html Tue Nov 11 22:37:25 2003 +0000 +++ b/templates/minimal/html/user.item.html Wed Nov 12 01:00:59 2003 +0000 @@ -12,7 +12,6 @@ <form method="POST" onSubmit="return submit_once()" enctype="multipart/form-data" tal:condition="context/is_edit_ok"> -<input type="hidden" name=":required" value="username,address"> <table class="form"> <tr> @@ -45,7 +44,10 @@ </tr> <tr> - <td> </td> + <td> + <input type="hidden" name="@required" value="username,address"> + <input type="hidden" name="@template" value="item"> + </td> <td tal:content="structure context/submit">submit button here</td> </tr> </table>
