Code

Move templates/ to share/roundup/templates/
authorstefan <stefan@57a73879-2fb5-44c3-a270-3262357dd7e2>
Mon, 23 Feb 2009 15:31:29 +0000 (15:31 +0000)
committerstefan <stefan@57a73879-2fb5-44c3-a270-3262357dd7e2>
Mon, 23 Feb 2009 15:31:29 +0000 (15:31 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/roundup/trunk@4161 57a73879-2fb5-44c3-a270-3262357dd7e2

134 files changed:
demo.py
setup.py
share/roundup/templates/classic/.cvsignore [new file with mode: 0644]
share/roundup/templates/classic/TEMPLATE-INFO.txt [new file with mode: 0644]
share/roundup/templates/classic/detectors/.cvsignore [new file with mode: 0644]
share/roundup/templates/classic/detectors/messagesummary.py [new file with mode: 0644]
share/roundup/templates/classic/detectors/nosyreaction.py [new file with mode: 0644]
share/roundup/templates/classic/detectors/statusauditor.py [new file with mode: 0644]
share/roundup/templates/classic/detectors/userauditor.py [new file with mode: 0644]
share/roundup/templates/classic/extensions/README.txt [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.404.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.calendar.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.collision.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.help-empty.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.help-list.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.help-search.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.help-submit.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.help.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.index.html [new file with mode: 0644]
share/roundup/templates/classic/html/_generic.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/file.index.html [new file with mode: 0644]
share/roundup/templates/classic/html/file.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/help.html [new file with mode: 0644]
share/roundup/templates/classic/html/help_controls.js [new file with mode: 0644]
share/roundup/templates/classic/html/home.classlist.html [new file with mode: 0644]
share/roundup/templates/classic/html/home.html [new file with mode: 0644]
share/roundup/templates/classic/html/issue.index.html [new file with mode: 0644]
share/roundup/templates/classic/html/issue.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/issue.search.html [new file with mode: 0644]
share/roundup/templates/classic/html/keyword.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/msg.index.html [new file with mode: 0644]
share/roundup/templates/classic/html/msg.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/page.html [new file with mode: 0644]
share/roundup/templates/classic/html/query.edit.html [new file with mode: 0644]
share/roundup/templates/classic/html/query.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/style.css [new file with mode: 0644]
share/roundup/templates/classic/html/user.forgotten.html [new file with mode: 0644]
share/roundup/templates/classic/html/user.help-search.html [new file with mode: 0644]
share/roundup/templates/classic/html/user.help.html [new file with mode: 0644]
share/roundup/templates/classic/html/user.index.html [new file with mode: 0644]
share/roundup/templates/classic/html/user.item.html [new file with mode: 0644]
share/roundup/templates/classic/html/user.register.html [new file with mode: 0644]
share/roundup/templates/classic/html/user.rego_progress.html [new file with mode: 0644]
share/roundup/templates/classic/html/user_utils.js [new file with mode: 0644]
share/roundup/templates/classic/initial_data.py [new file with mode: 0644]
share/roundup/templates/classic/schema.py [new file with mode: 0644]
share/roundup/templates/minimal/.cvsignore [new file with mode: 0644]
share/roundup/templates/minimal/TEMPLATE-INFO.txt [new file with mode: 0644]
share/roundup/templates/minimal/detectors/.cvsignore [new file with mode: 0644]
share/roundup/templates/minimal/detectors/userauditor.py [new file with mode: 0644]
share/roundup/templates/minimal/extensions/README.txt [new file with mode: 0644]
share/roundup/templates/minimal/html/_generic.404.html [new file with mode: 0644]
share/roundup/templates/minimal/html/_generic.calendar.html [new file with mode: 0644]
share/roundup/templates/minimal/html/_generic.collision.html [new file with mode: 0644]
share/roundup/templates/minimal/html/_generic.help.html [new file with mode: 0644]
share/roundup/templates/minimal/html/_generic.index.html [new file with mode: 0644]
share/roundup/templates/minimal/html/_generic.item.html [new file with mode: 0644]
share/roundup/templates/minimal/html/help_controls.js [new file with mode: 0644]
share/roundup/templates/minimal/html/home.classlist.html [new file with mode: 0644]
share/roundup/templates/minimal/html/home.html [new file with mode: 0644]
share/roundup/templates/minimal/html/page.html [new file with mode: 0644]
share/roundup/templates/minimal/html/style.css [new file with mode: 0644]
share/roundup/templates/minimal/html/user.index.html [new file with mode: 0644]
share/roundup/templates/minimal/html/user.item.html [new file with mode: 0644]
share/roundup/templates/minimal/html/user.register.html [new file with mode: 0644]
share/roundup/templates/minimal/html/user.rego_progress.html [new file with mode: 0644]
share/roundup/templates/minimal/initial_data.py [new file with mode: 0644]
share/roundup/templates/minimal/schema.py [new file with mode: 0644]
templates/classic/.cvsignore [deleted file]
templates/classic/TEMPLATE-INFO.txt [deleted file]
templates/classic/detectors/.cvsignore [deleted file]
templates/classic/detectors/messagesummary.py [deleted file]
templates/classic/detectors/nosyreaction.py [deleted file]
templates/classic/detectors/statusauditor.py [deleted file]
templates/classic/detectors/userauditor.py [deleted file]
templates/classic/extensions/README.txt [deleted file]
templates/classic/html/_generic.404.html [deleted file]
templates/classic/html/_generic.calendar.html [deleted file]
templates/classic/html/_generic.collision.html [deleted file]
templates/classic/html/_generic.help-empty.html [deleted file]
templates/classic/html/_generic.help-list.html [deleted file]
templates/classic/html/_generic.help-search.html [deleted file]
templates/classic/html/_generic.help-submit.html [deleted file]
templates/classic/html/_generic.help.html [deleted file]
templates/classic/html/_generic.index.html [deleted file]
templates/classic/html/_generic.item.html [deleted file]
templates/classic/html/file.index.html [deleted file]
templates/classic/html/file.item.html [deleted file]
templates/classic/html/help.html [deleted file]
templates/classic/html/help_controls.js [deleted file]
templates/classic/html/home.classlist.html [deleted file]
templates/classic/html/home.html [deleted file]
templates/classic/html/issue.index.html [deleted file]
templates/classic/html/issue.item.html [deleted file]
templates/classic/html/issue.search.html [deleted file]
templates/classic/html/keyword.item.html [deleted file]
templates/classic/html/msg.index.html [deleted file]
templates/classic/html/msg.item.html [deleted file]
templates/classic/html/page.html [deleted file]
templates/classic/html/query.edit.html [deleted file]
templates/classic/html/query.item.html [deleted file]
templates/classic/html/style.css [deleted file]
templates/classic/html/user.forgotten.html [deleted file]
templates/classic/html/user.help-search.html [deleted file]
templates/classic/html/user.help.html [deleted file]
templates/classic/html/user.index.html [deleted file]
templates/classic/html/user.item.html [deleted file]
templates/classic/html/user.register.html [deleted file]
templates/classic/html/user.rego_progress.html [deleted file]
templates/classic/html/user_utils.js [deleted file]
templates/classic/initial_data.py [deleted file]
templates/classic/schema.py [deleted file]
templates/minimal/.cvsignore [deleted file]
templates/minimal/TEMPLATE-INFO.txt [deleted file]
templates/minimal/detectors/.cvsignore [deleted file]
templates/minimal/detectors/userauditor.py [deleted file]
templates/minimal/extensions/README.txt [deleted file]
templates/minimal/html/_generic.404.html [deleted file]
templates/minimal/html/_generic.calendar.html [deleted file]
templates/minimal/html/_generic.collision.html [deleted file]
templates/minimal/html/_generic.help.html [deleted file]
templates/minimal/html/_generic.index.html [deleted file]
templates/minimal/html/_generic.item.html [deleted file]
templates/minimal/html/help_controls.js [deleted file]
templates/minimal/html/home.classlist.html [deleted file]
templates/minimal/html/home.html [deleted file]
templates/minimal/html/page.html [deleted file]
templates/minimal/html/style.css [deleted file]
templates/minimal/html/user.index.html [deleted file]
templates/minimal/html/user.item.html [deleted file]
templates/minimal/html/user.register.html [deleted file]
templates/minimal/html/user.rego_progress.html [deleted file]
templates/minimal/initial_data.py [deleted file]
templates/minimal/schema.py [deleted file]

diff --git a/demo.py b/demo.py
index b911541c3c48b20d0af5817f88195549ccd290c6..66b1e3500d8f169919f3436d09804fbcce8d405f 100644 (file)
--- a/demo.py
+++ b/demo.py
@@ -127,7 +127,7 @@ def demo_main():
             backend = sys.argv[-2]
         else:
             backend = 'anydbm'
-        install_demo(home, backend, os.path.join('templates', 'classic'))
+        install_demo(home, backend, os.path.join('share', 'roundup', 'templates', 'classic'))
     run_demo(home)
 
 if __name__ == '__main__':
index 27d533de624900485dc3d4ae739048c4f2d44965..3a0209762d63fa4e66390c17e5056259b382919d 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -78,7 +78,7 @@ def main():
 
     # add the templates to the data files lists
     from roundup.init import listTemplates
-    templates = [t['path'] for t in listTemplates('templates').values()]
+    templates = [t['path'] for t in listTemplates(os.path.join('share','roundup','templates')).values()]
     for tdir in templates:
         # scan for data files
         for idir in '. detectors extensions html'.split():
diff --git a/share/roundup/templates/classic/.cvsignore b/share/roundup/templates/classic/.cvsignore
new file mode 100644 (file)
index 0000000..d90d51d
--- /dev/null
@@ -0,0 +1,4 @@
+*.pyc
+*.pyo
+htmlbase.py
+*.cover
diff --git a/share/roundup/templates/classic/TEMPLATE-INFO.txt b/share/roundup/templates/classic/TEMPLATE-INFO.txt
new file mode 100644 (file)
index 0000000..1c20d54
--- /dev/null
@@ -0,0 +1,7 @@
+Name: classic
+Description: This is a generic issue tracker that may be used to track bugs,
+             feature requests, project issues or any number of other types
+             of issues. Most users of Roundup will find that this template
+             suits them, with perhaps a few customisations.
+Intended-For: All first-time Roundup users
+
diff --git a/share/roundup/templates/classic/detectors/.cvsignore b/share/roundup/templates/classic/detectors/.cvsignore
new file mode 100644 (file)
index 0000000..4162d5e
--- /dev/null
@@ -0,0 +1,3 @@
+*.pyc
+*.pyo
+*.cover
diff --git a/share/roundup/templates/classic/detectors/messagesummary.py b/share/roundup/templates/classic/detectors/messagesummary.py
new file mode 100644 (file)
index 0000000..def2e82
--- /dev/null
@@ -0,0 +1,19 @@
+#$Id: messagesummary.py,v 1.2 2007-04-03 06:47:21 a1s Exp $
+
+from roundup.mailgw import parseContent
+
+def summarygenerator(db, cl, nodeid, newvalues):
+    ''' If the message doesn't have a summary, make one for it.
+    '''
+    if newvalues.has_key('summary') or not newvalues.has_key('content'):
+        return
+
+    summary, content = parseContent(newvalues['content'], config=db.config)
+    newvalues['summary'] = summary
+
+
+def init(db):
+    # fire before changes are made
+    db.msg.audit('create', summarygenerator)
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/share/roundup/templates/classic/detectors/nosyreaction.py b/share/roundup/templates/classic/detectors/nosyreaction.py
new file mode 100644 (file)
index 0000000..c732fd0
--- /dev/null
@@ -0,0 +1,143 @@
+#
+# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
+# This module is free software, and you may redistribute it and/or modify
+# under the same terms as Python, so long as this copyright message and
+# disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
+# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
+# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# 
+#$Id: nosyreaction.py,v 1.4 2005-04-04 08:47:14 richard Exp $
+
+import sets
+
+from roundup import roundupdb, hyperdb
+
+def nosyreaction(db, cl, nodeid, oldvalues):
+    ''' A standard detector is provided that watches for additions to the
+        "messages" property.
+        
+        When a new message is added, the detector sends it to all the users on
+        the "nosy" list for the issue that are not already on the "recipients"
+        list of the message.
+        
+        Those users are then appended to the "recipients" property on the
+        message, so multiple copies of a message are never sent to the same
+        user.
+        
+        The journal recorded by the hyperdatabase on the "recipients" property
+        then provides a log of when the message was sent to whom. 
+    '''
+    # send a copy of all new messages to the nosy list
+    for msgid in determineNewMessages(cl, nodeid, oldvalues):
+        try:
+            cl.nosymessage(nodeid, msgid, oldvalues)
+        except roundupdb.MessageSendError, message:
+            raise roundupdb.DetectorError, message
+
+def determineNewMessages(cl, nodeid, oldvalues):
+    ''' Figure a list of the messages that are being added to the given
+        node in this transaction.
+    '''
+    messages = []
+    if oldvalues is None:
+        # the action was a create, so use all the messages in the create
+        messages = cl.get(nodeid, 'messages')
+    elif oldvalues.has_key('messages'):
+        # the action was a set (so adding new messages to an existing issue)
+        m = {}
+        for msgid in oldvalues['messages']:
+            m[msgid] = 1
+        messages = []
+        # figure which of the messages now on the issue weren't there before
+        for msgid in cl.get(nodeid, 'messages'):
+            if not m.has_key(msgid):
+                messages.append(msgid)
+    return messages
+
+def updatenosy(db, cl, nodeid, newvalues):
+    '''Update the nosy list for changes to the assignedto
+    '''
+    # nodeid will be None if this is a new node
+    current_nosy = sets.Set()
+    if nodeid is None:
+        ok = ('new', 'yes')
+    else:
+        ok = ('yes',)
+        # old node, get the current values from the node if they haven't
+        # changed
+        if not newvalues.has_key('nosy'):
+            nosy = cl.get(nodeid, 'nosy')
+            for value in nosy:
+                current_nosy.add(value)
+
+    # if the nosy list changed in this transaction, init from the new value
+    if newvalues.has_key('nosy'):
+        nosy = newvalues.get('nosy', [])
+        for value in nosy:
+            if not db.hasnode('user', value):
+                continue
+            current_nosy.add(value)
+
+    new_nosy = sets.Set(current_nosy)
+
+    # add assignedto(s) to the nosy list
+    if newvalues.has_key('assignedto') and newvalues['assignedto'] is not None:
+        propdef = cl.getprops()
+        if isinstance(propdef['assignedto'], hyperdb.Link):
+            assignedto_ids = [newvalues['assignedto']]
+        elif isinstance(propdef['assignedto'], hyperdb.Multilink):
+            assignedto_ids = newvalues['assignedto']
+        for assignedto_id in assignedto_ids:
+            new_nosy.add(assignedto_id)
+
+    # see if there's any new messages - if so, possibly add the author and
+    # recipient to the nosy
+    if newvalues.has_key('messages'):
+        if nodeid is None:
+            ok = ('new', 'yes')
+            messages = newvalues['messages']
+        else:
+            ok = ('yes',)
+            # figure which of the messages now on the issue weren't
+            oldmessages = cl.get(nodeid, 'messages')
+            messages = []
+            for msgid in newvalues['messages']:
+                if msgid not in oldmessages:
+                    messages.append(msgid)
+
+        # configs for nosy modifications
+        add_author = getattr(db.config, 'ADD_AUTHOR_TO_NOSY', 'new')
+        add_recips = getattr(db.config, 'ADD_RECIPIENTS_TO_NOSY', 'new')
+
+        # now for each new message:
+        msg = db.msg
+        for msgid in messages:
+            if add_author in ok:
+                authid = msg.get(msgid, 'author')
+                new_nosy.add(authid)
+
+            # add on the recipients of the message
+            if add_recips in ok:
+                for recipient in msg.get(msgid, 'recipients'):
+                    new_nosy.add(recipient)
+
+    if current_nosy != new_nosy:
+        # that's it, save off the new nosy list
+        newvalues['nosy'] = list(new_nosy)
+
+def init(db):
+    db.issue.react('create', nosyreaction)
+    db.issue.react('set', nosyreaction)
+    db.issue.audit('create', updatenosy)
+    db.issue.audit('set', updatenosy)
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/share/roundup/templates/classic/detectors/statusauditor.py b/share/roundup/templates/classic/detectors/statusauditor.py
new file mode 100644 (file)
index 0000000..75e4962
--- /dev/null
@@ -0,0 +1,85 @@
+# Copyright (c) 2002 ekit.com Inc (http://www.ekit-inc.com/)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included in
+#   all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#$Id: statusauditor.py,v 1.5 2004-03-27 00:01:48 richard Exp $
+
+def chatty(db, cl, nodeid, newvalues):
+    ''' If the issue is currently 'unread', 'resolved', 'done-cbb' or None,
+        then set it to 'chatting'
+    '''
+    # don't fire if there's no new message (ie. chat)
+    if not newvalues.has_key('messages'):
+        return
+    if newvalues['messages'] == cl.get(nodeid, 'messages'):
+        return
+
+    # get the chatting state ID
+    try:
+        chatting_id = db.status.lookup('chatting')
+    except KeyError:
+        # no chatting state, ignore all this stuff
+        return
+
+    # get the current value
+    current_status = cl.get(nodeid, 'status')
+
+    # see if there's an explicit change in this transaction
+    if newvalues.has_key('status'):
+        # yep, skip
+        return
+
+    # determine the id of 'unread', 'resolved' and 'chatting'
+    fromstates = []
+    for state in 'unread resolved done-cbb'.split():
+        try:
+            fromstates.append(db.status.lookup(state))
+        except KeyError:
+            pass
+
+    # ok, there's no explicit change, so check if we are in a state that
+    # should be changed
+    if current_status in fromstates + [None]:
+        # yep, we're now chatting
+        newvalues['status'] = chatting_id
+
+
+def presetunread(db, cl, nodeid, newvalues):
+    ''' Make sure the status is set on new issues
+    '''
+    if newvalues.has_key('status') and newvalues['status']:
+        return
+
+    # get the unread state ID
+    try:
+        unread_id = db.status.lookup('unread')
+    except KeyError:
+        # no unread state, ignore all this stuff
+        return
+
+    # ok, do it
+    newvalues['status'] = unread_id
+
+
+def init(db):
+    # fire before changes are made
+    db.issue.audit('set', chatty)
+    db.issue.audit('create', presetunread)
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/share/roundup/templates/classic/detectors/userauditor.py b/share/roundup/templates/classic/detectors/userauditor.py
new file mode 100644 (file)
index 0000000..fc71a1c
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included in
+#   all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#$Id: userauditor.py,v 1.9 2007-09-12 21:11:13 jpend Exp $
+
+import re
+
+# regular expression thanks to: http://www.regular-expressions.info/email.html
+# this is the "99.99% solution for syntax only".
+email_regexp = (r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*", r"(localhost|(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]))")
+email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
+email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
+
+def valid_address(address):
+    ''' If we see an @-symbol in the address then check against the full
+        RFC syntax. Otherwise it is a local-only address so only check
+        the local part of the RFC syntax.
+    '''
+    if '@' in address:
+        return email_rfc.match(address)
+    else:
+        return email_local.match(address)
+
+def get_addresses(user):
+    ''' iterate over all known addresses in a newvalues dict
+        this takes of the address/alterate_addresses handling
+    '''
+    if user.has_key('address'):
+        yield user['address']
+    if user.get('alternate_addresses', None):
+        for address in user['alternate_addresses'].split('\n'):
+            yield address
+
+def audit_user_fields(db, cl, nodeid, newvalues):
+    ''' Make sure user properties are valid.
+
+        - email address is syntactically valid
+        - email address is unique
+        - roles specified exist
+        - timezone is valid
+    '''
+
+    for address in get_addresses(newvalues):
+        if not valid_address(address):
+            raise ValueError, 'Email address syntax is invalid'
+
+        check_main = db.user.stringFind(address=address)
+        # make sure none of the alts are owned by anyone other than us (x!=nodeid)
+        check_alts = [x for x in db.user.filter(None, {'alternate_addresses' : address}) if x != nodeid]
+        if check_main or check_alts:
+            raise ValueError, 'Email address %s already in use' % address
+
+    for rolename in [r.lower().strip() for r in newvalues.get('roles', '').split(',')]:
+            if rolename and not db.security.role.has_key(rolename):
+                raise ValueError, 'Role "%s" does not exist'%rolename
+
+    tz = newvalues.get('timezone', None)
+    if tz:
+        # if they set a new timezone validate the timezone by attempting to
+        # use it before we store it to the db.
+        import roundup.date
+        import datetime
+        try:
+            TZ = roundup.date.get_timezone(tz)
+            dt = datetime.datetime.now()
+            local = TZ.localize(dt).utctimetuple()
+        except IOError:
+            raise ValueError, 'Timezone "%s" does not exist' % tz
+        except ValueError:
+            raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz
+
+def init(db):
+    # fire before changes are made
+    db.user.audit('set', audit_user_fields)
+    db.user.audit('create', audit_user_fields)
+
+# vim: sts=4 sw=4 et si
diff --git a/share/roundup/templates/classic/extensions/README.txt b/share/roundup/templates/classic/extensions/README.txt
new file mode 100644 (file)
index 0000000..ff4dff3
--- /dev/null
@@ -0,0 +1,6 @@
+This directory is for tracker extensions:
+
+- CGI Actions
+- Templating functions
+
+See the customisation doc for more information.
diff --git a/share/roundup/templates/classic/html/_generic.404.html b/share/roundup/templates/classic/html/_generic.404.html
new file mode 100644 (file)
index 0000000..71c9e0e
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Item Not Found</title>
+</head>
+
+<body>
+There is no <span tal:content="context/_classname" /> with id <span tal:content="context/id"/>
+</body>
+</html>
diff --git a/share/roundup/templates/classic/html/_generic.calendar.html b/share/roundup/templates/classic/html/_generic.calendar.html
new file mode 100644 (file)
index 0000000..0f9cf40
--- /dev/null
@@ -0,0 +1,18 @@
+<!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" />
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" />
+  <title tal:content="string:Roundup Calendar"></title>
+  <script language="Javascript"
+          type="text/javascript"
+          tal:content="structure string:
+          // this is the name of the field in the original form that we're working on
+          form  = window.opener.document.${request/form/form/value};
+          field = '${request/form/property/value}';" >
+  </script>
+ </head>
+ <body class="body"
+       tal:content="structure python:utils.html_calendar(request)">
+ </body>
+</html>
diff --git a/share/roundup/templates/classic/html/_generic.collision.html b/share/roundup/templates/classic/html/_generic.collision.html
new file mode 100644 (file)
index 0000000..2a2768a
--- /dev/null
@@ -0,0 +1,16 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> Edit Collision - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<tal:block metal:fill-slot="body_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> Edit Collision</tal:block>
+
+<td class="content" metal:fill-slot="content" i18n:translate="
+  There has been a collision. Another user updated this node
+  while you were editing. Please <a href='${context}'>reload</a>
+  the node and review your edits.
+"><span tal:replace="context/designator" i18n:name="context" />
+</td>
+</tal:block>
diff --git a/share/roundup/templates/classic/html/_generic.help-empty.html b/share/roundup/templates/classic/html/_generic.help-empty.html
new file mode 100644 (file)
index 0000000..65469fc
--- /dev/null
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>Empty page (no search performed yet)</title>
+  </head>
+  <body>
+    <p i18n:translate="">Please specify your search parameters!</p>
+  </body>
+</html>
diff --git a/share/roundup/templates/classic/html/_generic.help-list.html b/share/roundup/templates/classic/html/_generic.help-list.html
new file mode 100644 (file)
index 0000000..66cbb90
--- /dev/null
@@ -0,0 +1,83 @@
+<!-- $Id: _generic.help-list.html,v 1.2 2008-03-01 08:18:07 richard Exp $ vim: sw=2 ts=8 et
+--><html tal:define="vok context/is_view_ok">
+  <head>
+    <title>Search result for user helper</title>
+    <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+    <script language="Javascript" type="text/javascript"
+        tal:content="structure string:<!--
+        // this is the name of the field in the original form that we're working on
+        form  = parent.opener.document.${request/form/form/value};
+        field  = '${request/form/property/value}';
+    //-->"></script>
+    <script src="@@file/help_controls.js" type="text/javascript"></script>
+<script type="text/javascript"><!--
+var text_field = parent.submit.document.frm_help.text_preview;
+//--></script>
+  </head>
+  <body>
+    <pre tal:content="request/env/QUERY_STRING" tal:condition=false />
+
+  <p tal:condition="not:vok" i18n:translate="">You are not
+  allowed to view this page.</p>
+
+  <tal:if condition="context/is_view_ok">
+  <tal:def define="batch request/batch;">
+  <form name=dummyform>
+    <table width="100%"
+      tal:define="template string:help-list"
+      metal:use-macro="templates/help/macros/batch_navi"
+      >
+      <tr class="navigation">
+       <th>
+        <a href="#">&lt;&lt; previous</a>
+       </th>
+       <th i18n:translate="">1..25 out of 50
+       </th>
+       <th>
+        <a href="#">next &gt;&gt;</a>
+       </th>
+      </tr>
+     </table>
+
+  <form name=dummyform>
+  <table class="classhelp"
+    tal:define="
+       props python:request.form['properties'].value.split(',');
+       legend templates/help/macros/legend;
+    "><thead>
+      <tr metal:use-macro="legend">
+         <th>&nbsp;<b>x</b></th>
+         <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
+       </tr>
+     </thead>
+     <tfoot tal:condition=true>
+       <tr metal:use-macro="legend" />
+     </tfoot>
+     <tbody>
+       <tr tal:repeat="item batch">
+         <tal:block tal:define="attr python:item[props[0]]" >
+           <td>
+             <input name="check"
+             onclick="switch_val(text_field, this);" type="checkbox"
+             tal:attributes="value attr; id string:id_$attr" />
+             </td>
+             <td tal:repeat="prop props">
+                 <label class="classhelp-label"
+                        tal:attributes="for string:id_$attr"
+                        tal:content="python:item[prop]"></label>
+             </td>
+           </tal:block>
+         </tr>
+       </tbody>
+     </table>
+   </form>
+     </tal:def>
+     </tal:if>
+     
+     <pre tal:content=request tal:condition=false />
+     <script type="text/javascript"><!--
+       parent.submit.document.frm_help.cb_listpresent.checked=true;
+       reviseList_framed(document.dummyform, text_field)
+     //--></script>
+  </body>
+</html>
diff --git a/share/roundup/templates/classic/html/_generic.help-search.html b/share/roundup/templates/classic/html/_generic.help-search.html
new file mode 100644 (file)
index 0000000..01d657e
--- /dev/null
@@ -0,0 +1,13 @@
+<html>
+  <head>
+    <title>Frame for search input fields</title>
+  </head>
+  <body>
+    <p i18n:translate="">Generic template
+    <span tal:replace="request/template" i18n:name="template">help-search</span>
+    or version for class
+    <span tal:replace="request/classname" i18n:name="classname">user</span>
+    is not yet implemented</p>
+  </body>
+</html>
+
diff --git a/share/roundup/templates/classic/html/_generic.help-submit.html b/share/roundup/templates/classic/html/_generic.help-submit.html
new file mode 100644 (file)
index 0000000..b13aa4a
--- /dev/null
@@ -0,0 +1,73 @@
+<html>
+  <head>
+      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+      <meta http-equiv="Content-Type"
+       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
+      <tal:block tal:condition="python:request.form.has_key('property')">
+      <title>Generic submit page for framed helper windows</title>
+      <script language="Javascript" type="text/javascript"
+          tal:content="structure string:<!--
+// this is the name of the field in the original form that we're working on
+form  = parent.opener.document.${request/form/form/value};
+callingform=form
+field  = '${request/form/property/value}';
+var listform = null
+function listPresent() {
+  return document.frm_help.cb_listpresent.checked
+}
+function getListForm() {
+  if (listPresent()) {
+    return parent.list.document.forms.dummyform
+  } else {
+    return null
+  }
+}
+
+
+function checkListForm() {
+  // global listform
+  if (listform != null)
+    if (parent.list.document.dummyform) {
+      listform = parent.list.document.dummyform
+      alert(listform)
+    }
+
+  var bol= listform != null
+  alert('checkListForm: bol='+bol)
+  return bol
+}
+//-->">
+      </script>
+      <script src="@@file/help_controls.js" type="text/javascript"></script>
+      </tal:block>
+  </head>
+ <body class="body" onload="parent.focus();" id="submit">
+ <pre tal:content="request/env/QUERY_STRING" tal:condition=false />
+ <form name="frm_help"
+       tal:define="batch request/batch;
+       props python:request.form['properties'].value.split(',')"
+       class="help-submit"
+       id="classhelp-controls">
+     <div style="width:100%;text-align:left;margin-bottom:0.2em">
+       <input type="text" name="text_preview" size="24" class="preview"
+       onchange="f=getListForm();if(f){ reviseList_framed(f, this)};"
+       />
+     </div>
+     <input type=checkbox name="cb_listpresent" readonly="readonly" style="display:none">
+     <input type="button" id="btn_cancel"
+            value=" Cancel " onclick="parent.close();return false;"
+            i18n:attributes="value" />
+     <input type="reset" id="btn_reset"
+     onclick="text_field.value=original_field;f=getListForm();if (f) {reviseList_framed(f, this)};return false"
+            />
+     <input type="submit" id="btn_apply" class="apply"
+            value=" Apply " onclick="callingform[field].value=text_field.value; parent.close();"
+            i18n:attributes="value" />
+ </form>
+ <script type="text/javascript"><!--
+var text_field = document.frm_help.text_preview;
+original_field=form[field].value;
+text_field.value=original_field;
+//--></script>
+ </body>
+</html>
diff --git a/share/roundup/templates/classic/html/_generic.help.html b/share/roundup/templates/classic/html/_generic.help.html
new file mode 100644 (file)
index 0000000..069c0a6
--- /dev/null
@@ -0,0 +1,98 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html tal:define="property request/form/property/value" >
+  <head>
+      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+      <meta http-equiv="Content-Type"
+       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
+      <tal:block tal:condition="python:request.form.has_key('property')">
+      <title i18n:translate=""><tal:x i18n:name="property"
+       tal:content="property" i18n:translate="" /> help - <span i18n:name="tracker"
+       tal:replace="config/TRACKER_NAME" /></title>
+      <script language="Javascript" type="text/javascript"
+          tal:content="structure string:
+          // this is the name of the field in the original form that we're working on
+          form  = window.opener.document.${request/form/form/value};
+          field  = '${request/form/property/value}';">
+      </script>
+      <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="batch request/batch;
+                   props python:request.form['properties'].value.split(',')">
+
+     <div id="classhelp-controls">
+       <!--input type="button" name="btn_clear"
+              value="Clear" onClick="clearList()"/ -->
+       <input type="text" name="text_preview" size="24" class="preview"
+              onchange="reviseList(this.value);"/>
+       <input type="button" name="btn_reset"
+              value=" Cancel " onclick="resetList(); window.close();"
+              i18n:attributes="value" />
+       <input type="button" name="btn_apply" class="apply"
+              value=" Apply " onclick="updateList(); window.close();"
+              i18n:attributes="value" />
+     </div>
+     <table width="100%">
+      <tr class="navigation">
+       <th>
+        <a tal:define="prev batch/previous" tal:condition="prev"
+           tal:attributes="href python:request.indexargs_url(request.classname,
+           {'@template':'help', 'property': request.form['property'].value,
+            'properties': request.form['properties'].value,
+            'form': request.form['form'].value,
+            'type': request.form['type'].value,
+            '@startwith':prev.first, '@pagesize':prev.size})"
+           i18n:translate="" >&lt;&lt; previous</a>
+        &nbsp;
+       </th>
+       <th i18n:translate=""><span tal:replace="batch/start" i18n:name="start"
+        />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
+        /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
+        />
+       </th>
+       <th>
+        <a tal:define="next batch/next" tal:condition="next"
+           tal:attributes="href python:request.indexargs_url(request.classname,
+           {'@template':'help', 'property': request.form['property'].value,
+            'properties': request.form['properties'].value,
+            'form': request.form['form'].value,
+            'type': request.form['type'].value,
+            '@startwith':next.first, '@pagesize':next.size})"
+           i18n:translate="" >next &gt;&gt;</a>
+        &nbsp;
+       </th>
+      </tr>
+     </table>
+
+     <table class="classhelp">
+       <tr>
+           <th>&nbsp;<b>x</b></th>
+           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
+       </tr>
+       <tr tal:repeat="item batch">
+         <tal:block tal:define="attr python:item[props[0]]" >
+           <td>
+             <input name="check"
+                 onclick="updatePreview();"
+                 tal:attributes="type python:request.form['type'].value;
+                                 value attr; id string:id_$attr" />
+             </td>
+             <td tal:repeat="prop props">
+                 <label class="classhelp-label"
+                        tal:attributes="for string:id_$attr"
+                        tal:content="python:item[prop]"></label>
+             </td>
+           </tal:block>
+       </tr>
+       <tr>
+           <th>&nbsp;<b>x</b></th>
+           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
+       </tr>
+     </table>
+
+ </form>
+ </body>
+</html>
diff --git a/share/roundup/templates/classic/html/_generic.index.html b/share/roundup/templates/classic/html/_generic.index.html
new file mode 100644 (file)
index 0000000..a41ab0a
--- /dev/null
@@ -0,0 +1,70 @@
+<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<tal:block metal:fill-slot="body_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok()
+ or request.user.hasRole('Anonymous'))"
+ tal:omit-tag="python:1" i18n:translate=""
+>You are not allowed to view this page.</span>
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())
+ and request.user.hasRole('Anonymous')"
+ tal:omit-tag="python:1" i18n:translate=""
+>Please login with your username and password.</span>
+
+<tal:block tal:condition="context/is_edit_ok">
+<tal:block i18n:translate="">
+<p class="form-help">
+ You may edit the contents of the
+ <span tal:replace="request/classname" i18n:name="classname"/>
+ class using this form. Commas, newlines and double quotes (") must be
+ handled delicately. You may include commas and newlines by enclosing the
+ values in double-quotes ("). Double quotes themselves must be quoted by
+ doubling ("").
+</p>
+
+<p class="form-help">
+ Multilink properties have their multiple values colon (":") separated
+ (... ,"one:two:three", ...)
+</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>
+</tal:block>
+<form onSubmit="return submit_once()" method="POST"
+      tal:attributes="action context/designator">
+<textarea rows="15" style="width:90%" name="rows" tal:content="context/csv"></textarea>
+<br>
+<input type="hidden" name="@action" value="editCSV">
+<input type="submit" value="Edit Items" i18n:attributes="value">
+</form>
+</tal:block>
+
+<table tal:condition="context/is_only_view_ok" width="100%" class="list">
+ <tr>
+  <th tal:repeat="property context/propnames" tal:content="property">&nbsp;</th>
+ </tr>
+ <tal:block repeat="item context/list">
+ <tr tal:condition="item/is_view_ok"
+     tal:attributes="class python:['normal', 'alt'][repeat['item'].index%6/3]">
+  <td tal:repeat="property context/propnames"
+   tal:content="python: item[property] or default"
+  >&nbsp;</td>
+ </tr>
+ </tal:block>
+</table>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/_generic.item.html b/share/roundup/templates/classic/html/_generic.item.html
new file mode 100644 (file)
index 0000000..d9b98ae
--- /dev/null
@@ -0,0 +1,53 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<tal:block metal:fill-slot="body_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<div tal:condition="context/is_view_ok">
+
+<form method="POST" onSubmit="return submit_once()"
+      enctype="multipart/form-data" tal:condition="context/is_view_ok"
+      tal:attributes="action context/designator">
+
+<input type="hidden" name="@template" value="item">
+
+<table class="form">
+
+<tr tal:repeat="prop python:db[context._classname].properties()">
+ <tal:block tal:condition="python:prop._name not in ('id',
+   'creator', 'creation', 'actor', 'activity')">
+  <th tal:content="prop/_name"></th>
+  <td tal:content="structure python:context[prop._name].field()"></td>
+ </tal:block>
+</tr>
+<tr>
+ <td>&nbsp;</td>
+ <td colspan=3 tal:content="structure context/submit">
+  submit button will go here
+ </td>
+</tr>
+</table>
+
+</form>
+
+<tal:block tal:condition="context/id" tal:replace="structure context/history" />
+
+</div>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/file.index.html b/share/roundup/templates/classic/html/file.index.html
new file mode 100644 (file)
index 0000000..9717920
--- /dev/null
@@ -0,0 +1,31 @@
+<!-- dollarId: file.index,v 1.4 2002/01/23 05:10:27 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ >List of files - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+  i18n:translate="">List of files</span>
+<td class="content" metal:fill-slot="content">
+
+<table class="otherinfo" tal:define="batch request/batch">
+ <tr><th style="padding-right: 10" i18n:translate="">Download</th>
+     <th style="padding-right: 10" i18n:translate="">Content Type</th>
+     <th style="padding-right: 10" i18n:translate="">Uploaded By</th>
+     <th style="padding-right: 10" i18n:translate="">Date</th>
+ </tr>
+ <tr tal:repeat="file batch" tal:attributes="class python:['normal', 'alt'][repeat['file'].index%6/3]">
+  <td>
+   <a tal:attributes="href string:file${file/id}/${file/name}"
+      tal:content="file/name">dld link</a>
+  </td>
+  <td tal:content="file/type">content type</td>
+  <td tal:content="file/creator">creator's name</td>
+  <td tal:content="file/creation">creation date</td>
+ </tr>
+
+ <metal:block use-macro="templates/issue.index/macros/batch-footer" />
+
+</table>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/file.item.html b/share/roundup/templates/classic/html/file.item.html
new file mode 100644 (file)
index 0000000..d223fd7
--- /dev/null
@@ -0,0 +1,53 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">File display - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">File display</span>
+
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<form method="POST" onSubmit="return submit_once()"
+      enctype="multipart/form-data" tal:condition="context/is_view_ok"
+      tal:attributes="action context/designator">
+
+<table class="form">
+ <tr>
+  <th i18n:translate="">Name</th>
+  <td tal:content="structure context/name/field"></td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Content Type</th>
+  <td tal:content="structure context/type/field"></td>
+ </tr>
+
+ <tr>
+  <td>
+   &nbsp;
+   <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>
+</table>
+</form>
+
+<a tal:condition="python:context.id and context.is_view_ok()"
+ tal:attributes="href string:file${context/id}/${context/name}"
+ i18n:translate="">download</a>
+
+<tal:block tal:condition="context/id" tal:replace="structure context/history" />
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/help.html b/share/roundup/templates/classic/html/help.html
new file mode 100644 (file)
index 0000000..1571a6f
--- /dev/null
@@ -0,0 +1,38 @@
+<!--
+Macros for framed help windows
+-->
+
+<!-- legend for helper search results -->
+<thead>
+<tr metal:define-macro="legend">
+  <th><b>x</b></th>
+  <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
+</tr>
+</thead>
+
+<table width="100%"
+  metal:define-macro="batch_navi"
+  tal:define="prev batch/previous;
+  next batch/next;
+  "
+  tal:condition="python:prev or next">
+  <tr class="navigation">
+   <th width="30%">
+    <a tal:condition="prev"
+       tal:attributes="href python:request.indexargs_url(request.classname, {'@template':'help-list', 'property': request.form['property'].value, 'properties': request.form['properties'].value, 'form': request.form['form'].value, '@startwith':prev.first, '@pagesize':prev.size})"
+       i18n:translate="" >&lt;&lt; previous</a>
+    &nbsp;
+   </th>
+   <th i18n:translate="" width="40%"><span tal:replace="batch/start" i18n:name="start"
+    />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
+    /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
+    />
+   </th>
+   <th width="30%">
+    <a tal:condition="next"
+       tal:attributes="href python:request.indexargs_url(request.classname, {'@template':'help-list', 'property': request.form['property'].value, 'properties': request.form['properties'].value, 'form': request.form['form'].value, '@startwith':next.first, '@pagesize':next.size})"
+       i18n:translate="" >next &gt;&gt;</a>
+    &nbsp;
+   </th>
+  </tr>
+ </table>
diff --git a/share/roundup/templates/classic/html/help_controls.js b/share/roundup/templates/classic/html/help_controls.js
new file mode 100644 (file)
index 0000000..480170a
--- /dev/null
@@ -0,0 +1,324 @@
+// initial values for either Nosy, Superseder, Keyword and Waiting On,
+// depending on which has called
+original_field = form[field].value;
+
+// Some browsers (ok, IE) don't define the "undefined" variable.
+undefined = document.geez_IE_is_really_friggin_annoying;
+
+function trim(value) {
+  var temp = value;
+  var obj = /^(\s*)([\W\w]*)(\b\s*$)/;
+  if (obj.test(temp)) { temp = temp.replace(obj, '$2'); }
+  var obj = /  /g;
+  while (temp.match(obj)) { temp = temp.replace(obj, " "); }
+  return temp;
+}
+
+function determineList() {
+     // generate a comma-separated list of the checked items
+     var list = new String('');
+
+     // either a checkbox object or an array of checkboxes
+     var check = document.frm_help.check;
+
+     if ((check.length == undefined) && (check.checked != undefined)) {
+         // only one checkbox on page
+         if (check.checked) {
+             list = check.value;
+         }
+     } else {
+         // array of checkboxes
+         for (box=0; box < check.length; box++) {
+             if (check[box].checked) {
+                 if (list.length == 0) {
+                     separator = '';
+                 }
+                 else {
+                     separator = ',';
+                 }
+                 // we used to use an Array and push / join, but IE5.0 sux
+                 list = list + separator + check[box].value;
+             }
+         }
+     }
+     return list;
+}
+
+/**
+ * update the field in the opening window;
+ * the text_field variable must be set in the calling page
+ */
+function updateOpener() {
+  // write back to opener window
+  if (document.frm_help.check==undefined) { return; }
+  form[field].value = text_field.value;
+}
+
+function updateList() {
+  // write back to opener window
+  if (document.frm_help.check==undefined) { return; }
+  form[field].value = determineList();
+}
+
+function updatePreview() {
+  // update the preview box
+  if (document.frm_help.check==undefined) { return; }
+  writePreview(determineList());
+}
+
+function clearList() {
+  // uncheck all checkboxes
+  if (document.frm_help.check==undefined) { return; }
+  for (box=0; box < document.frm_help.check.length; box++) {
+      document.frm_help.check[box].checked = false;
+  }
+}
+
+function reviseList_framed(form, textfield) {
+  // update the checkboxes based on the preview field
+  // alert('reviseList_framed')
+  // alert(form)
+  if (form.check==undefined)
+      return;
+  // alert(textfield)
+  var to_check;
+  var list = textfield.value.split(",");
+  if (form.check.length==undefined) {
+      check = form.check;
+      to_check = false;
+      for (val in list) {
+          if (check.value==trim(list[val])) {
+              to_check = true;
+              break;
+          }
+      }
+      check.checked = to_check;
+  } else {
+    for (box=0; box < form.check.length; box++) {
+      check = form.check[box];
+      to_check = false;
+      for (val in list) {
+          if (check.value==trim(list[val])) {
+              to_check = true;
+              break;
+          }
+      }
+      check.checked = to_check;
+    }
+  }
+}
+
+function reviseList(vals) {
+  // update the checkboxes based on the preview field
+  if (document.frm_help.check==undefined) { return; }
+  var to_check;
+  var list = vals.split(",");
+  if (document.frm_help.check.length==undefined) {
+      check = document.frm_help.check;
+      to_check = false;
+      for (val in list) {
+          if (check.value==trim(list[val])) {
+              to_check = true;
+              break;
+          }
+      }
+      check.checked = to_check;
+  } else {
+    for (box=0; box < document.frm_help.check.length; box++) {
+      check = document.frm_help.check[box];
+      to_check = false;
+      for (val in list) {
+          if (check.value==trim(list[val])) {
+              to_check = true;
+              break;
+          }
+      }
+      check.checked = to_check;
+    }
+  }
+}
+
+function resetList() {
+  // reset preview and check boxes to initial values
+  if (document.frm_help.check==undefined) { return; }
+  writePreview(original_field);
+  reviseList(original_field);
+}
+
+function writePreview(val) {
+   // writes a value to the text_preview
+   document.frm_help.text_preview.value = val;
+}
+
+function focusField(name) {
+    for(i=0; i < document.forms.length; ++i) {
+      var obj = document.forms[i].elements[name];
+      if (obj && obj.focus) {obj.focus();}
+    }
+}
+
+function selectField(name) {
+    for(i=0; i < document.forms.length; ++i) {
+      var obj = document.forms[i].elements[name];
+      if (obj && obj.focus){obj.focus();}
+      if (obj && obj.select){obj.select();}
+    }
+}
+
+function checkRequiredFields(fields)
+{
+    var bonk='';
+    var res='';
+    var argv = checkRequiredFields.arguments;
+    var argc = argv.length;
+    var input = '';
+    var val='';
+
+    for (var i=0; i < argc; i++) {
+        fi = argv[i];
+        input = document.getElementById(fi);
+        if (input) {
+            val = input.value
+            if (val == '' || val == '-1' || val == -1) {
+                if (res == '') {
+                    res = fi;
+                    bonk = input;
+                } else {
+                    res += ', '+fi;
+                }
+            }
+        } else {
+            alert('Field with id='+fi+' not found!')
+        }
+    }
+    if (res == '') {
+        return submit_once();
+    } else {
+        alert('Missing value here ('+res+')!');
+        if (window.event && window.event.returnvalue) {
+            event.returnValue = 0;    // work-around for IE
+        }
+        bonk.focus();
+        return false;
+    }
+}
+
+/**
+ * seeks the given value (2nd argument)
+ * in the value of the given input element (1st argument),
+ * which is considered a list of values, separated by commas
+ */
+function has_value(input, val)
+{
+    var actval = input.value
+    var arr = feld.value.split(',');
+    var max = arr.length;
+    for (i=0;i<max;i++) {
+        if (trim(arr[i]) == val) {
+            return true
+        }
+    }
+    return false
+}
+
+/**
+ * Switch Value:
+ * change the value of the given input field (might be of type text or hidden),
+ * adding or removing the value of the given checkbox field (might be a radio
+ * button as well)
+ *
+ * This function doesn't care whether or not the checkboxes of all values of
+ * interest are present; but of course it doesn't have total control of the
+ * text field.
+ */
+function switch_val(text, check)
+{
+    var switched_val = check.value
+    var arr = text.value.split(',')
+    var max = arr.length
+    if (check.checked) {
+        for (i=0; i<max; i++) {
+            if (trim(arr[i]) == switched_val) {
+                return
+            }
+        }
+       if (text.value)
+            text.value = text.value+','+switched_val
+       else
+            text.value = switched_val
+    } else {
+        var neu = ''
+       var changed = false
+        for (i=0; i<max; i++) {
+            if (trim(arr[i]) == switched_val) {
+                changed=true
+            } else {
+                neu = neu+','+trim(arr[i])
+            }
+        }
+        if (changed) {
+            text.value = neu.substr(1)
+        }
+    }
+}
+
+/**
+ * append the given value (2nd argument) to an input field
+ * (1st argument) which contains comma-separated values;
+ * see --> remove_val()
+ *
+ * This will work nicely even for batched lists
+ */
+function append_val(name, val)
+{
+    var feld = document.itemSynopsis[name];
+    var actval = feld.value;
+    if (actval == '') {
+        feld.value = val
+    } else {
+        var arr = feld.value.split(',');
+        var max = arr.length;
+        for (i=0;i<max;i++) {
+            if (trim(arr[i]) == val) {
+                return
+            }
+        }
+        feld.value = actval+','+val
+    }
+}
+
+/**
+ * remove the given value (2nd argument) from the comma-separated values
+ * of the given input element (1st argument); see --> append_val()
+ */
+function remove_val(name, val)
+{
+    var feld = document.itemSynopsis[name];
+    var actval = feld.value;
+    var changed=false;
+    if (actval == '') {
+       return
+    } else {
+        var arr = feld.value.split(',');
+        var max = arr.length;
+        var neu = ''
+        for (i=0;i<max;i++) {
+            if (trim(arr[i]) == val) {
+                changed=true
+            } else {
+                neu = neu+','+trim(arr[i])
+            }
+        }
+        if (changed) {
+            feld.value = neu.substr(1)
+        }
+    }
+}
+
+/**
+ * give the focus to the element given by id
+ */
+function focus2id(name)
+{
+    document.getElementById(name).focus();
+}
diff --git a/share/roundup/templates/classic/html/home.classlist.html b/share/roundup/templates/classic/html/home.classlist.html
new file mode 100644 (file)
index 0000000..930306b
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">List of classes - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">List of classes</span>
+<td class="content" metal:fill-slot="content">
+<table class="classlist">
+
+<tal:block tal:repeat="cl db/classes">
+ <tr>
+  <th class="header" colspan="2" align="left">
+   <a tal:attributes="href string:${cl/classname}"
+      tal:content="python:cl.classname.capitalize()">classname</a>
+  </th>
+ </tr>
+ <tr tal:repeat="prop cl/properties">
+  <th tal:content="prop/_name">name</th>
+  <td tal:content="prop/_prop">type</td>
+ </tr>
+</tal:block>
+
+</table>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/home.html b/share/roundup/templates/classic/html/home.html
new file mode 100644 (file)
index 0000000..90d926a
--- /dev/null
@@ -0,0 +1,10 @@
+<!--
+ This is the default body that is displayed when people visit the
+ tracker. The tag below lists the currently open issues. You may
+ replace it with a greeting message, or a different list of issues or
+ whatever. It's a good idea to have the issues on the front page though
+-->
+<span tal:replace="structure python:db.issue.renderWith('index',
+    sort=[('-', 'activity')], group=[('+', 'priority')], filter=['status'],
+    columns=['id','activity','title','creator','assignedto', 'status'],
+    filterspec={'status':['-1','1','2','3','4','5','6','7']})" />
diff --git a/share/roundup/templates/classic/html/issue.index.html b/share/roundup/templates/classic/html/issue.index.html
new file mode 100644 (file)
index 0000000..581624c
--- /dev/null
@@ -0,0 +1,166 @@
+<!-- $Id: issue.index.html,v 1.29 2007-09-18 17:44:26 jpend Exp $ -->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" >
+  <span tal:omit-tag="true" i18n:translate="" >List of issues</span>
+  <span tal:condition="request/dispname"
+   tal:replace="python:' - %s '%request.dispname"
+  /> - <span tal:replace="config/TRACKER_NAME" />
+</title>
+<span metal:fill-slot="body_title" tal:omit-tag="true">
+  <span tal:omit-tag="true" i18n:translate="" >List of issues</span>
+  <span tal:condition="request/dispname"
+   tal:replace="python:' - %s' % request.dispname" />
+</span>
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<tal:block tal:define="batch request/batch" tal:condition="context/is_view_ok">
+ <table class="list">
+  <tr>
+   <th tal:condition="request/show/priority" i18n:translate="">Priority</th>
+   <th tal:condition="request/show/id" i18n:translate="">ID</th>
+   <th tal:condition="request/show/creation" i18n:translate="">Creation</th>
+   <th tal:condition="request/show/activity" i18n:translate="">Activity</th>
+   <th tal:condition="request/show/actor" i18n:translate="">Actor</th>
+   <th tal:condition="request/show/keyword" i18n:translate="">Keyword</th>
+   <th tal:condition="request/show/title" i18n:translate="">Title</th>
+   <th tal:condition="request/show/status" i18n:translate="">Status</th>
+   <th tal:condition="request/show/creator" i18n:translate="">Creator</th>
+   <th tal:condition="request/show/assignedto" i18n:translate="">Assigned&nbsp;To</th>
+  </tr>
+ <tal:block tal:repeat="i batch" condition=true>
+  <tr tal:define="group python:[r[1] for r in request.group]"
+      tal:condition="python:group and batch.propchanged(*group)">
+   <th tal:attributes="colspan python:len(request.columns)" class="group">
+    <tal:block tal:repeat="g group">
+     <tal:block i18n:translate="" tal:content="python:str(i[g]) or '(no %s set)'%g"/>
+    </tal:block>
+   </th>
+  </tr>
+
+  <tr>
+   <td tal:condition="request/show/priority"
+       tal:content="python:i.priority.plain() or default">&nbsp;</td>
+   <td tal:condition="request/show/id" tal:content="i/id">&nbsp;</td>
+   <td class="date" tal:condition="request/show/creation"
+       tal:content="i/creation/reldate">&nbsp;</td>
+   <td class="date" tal:condition="request/show/activity"
+       tal:content="i/activity/reldate">&nbsp;</td>
+   <td class="date" tal:condition="request/show/actor"
+       tal:content="python:i.actor.plain() or default">&nbsp;</td>
+   <td tal:condition="request/show/keyword"
+       tal:content="python:i.keyword.plain() or default">&nbsp;</td>
+   <td tal:condition="request/show/title">
+    <a tal:attributes="href string:issue${i/id}"
+               tal:content="python:str(i.title.plain(hyperlink=0)) or '[no title]'">title</a>
+   </td>
+   <td tal:condition="request/show/status"
+       i18n:translate=""
+       tal:content="python:i.status.plain() or default">&nbsp;</td>
+   <td tal:condition="request/show/creator"
+       tal:content="python:i.creator.plain() or default">&nbsp;</td>
+   <td tal:condition="request/show/assignedto"
+       tal:content="python:i.assignedto.plain() or default">&nbsp;</td>
+  </tr>
+
+ </tal:block>
+
+ <metal:index define-macro="batch-footer">
+ <tr tal:condition="batch">
+  <th tal:attributes="colspan python:len(request.columns)">
+   <table width="100%">
+    <tr class="navigation">
+     <th>
+      <a tal:define="prev batch/previous" tal:condition="prev"
+         tal:attributes="href python:request.indexargs_url(request.classname,
+         {'@startwith':prev.first, '@pagesize':prev.size})"
+         i18n:translate="">&lt;&lt; previous</a>
+      &nbsp;
+     </th>
+     <th i18n:translate=""><span tal:replace="batch/start" i18n:name="start"
+     />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
+     /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
+     /></th>
+     <th>
+      <a tal:define="next batch/next" tal:condition="next"
+         tal:attributes="href python:request.indexargs_url(request.classname,
+         {'@startwith':next.first, '@pagesize':next.size})"
+         i18n:translate="">next &gt;&gt;</a>
+      &nbsp;
+     </th>
+    </tr>
+   </table>
+  </th>
+ </tr>
+ </metal:index>
+</table>
+
+<a tal:attributes="href python:request.indexargs_url('issue',
+            {'@action':'export_csv'})" i18n:translate="">Download as CSV</a>
+
+<form method="GET" class="index-controls"
+    tal:attributes="action request/classname">
+
+ <table class="form" tal:define="n_sort python:2">
+  <tal:block tal:repeat="n python:range(n_sort)" tal:condition="batch">
+  <tr tal:define="key python:len(request.sort)>n and request.sort[n]">
+   <th>
+    <tal:block tal:condition="not:n" i18n:translate="">Sort on:</tal:block>
+   </th>
+   <td>
+    <select tal:attributes="name python:'@sort%d'%n">
+     <option value="" i18n:translate="">- nothing -</option>
+     <option tal:repeat="col context/properties"
+             tal:attributes="value col/_name;
+                             selected python:key and col._name == key[1]"
+             tal:content="col/_name"
+             i18n:translate="">column</option>
+    </select>
+   </td>
+   <th i18n:translate="">Descending:</th>
+   <td><input type="checkbox" tal:attributes="name python:'@sortdir%d'%n;
+              checked python:key and key[0] == '-'">
+   </td>
+  </tr>
+  </tal:block>
+  <tal:block tal:repeat="n python:range(n_sort)" tal:condition="batch">
+  <tr tal:define="key python:len(request.group)>n and request.group[n]">
+   <th>
+    <tal:block tal:condition="not:n" i18n:translate="">Group on:</tal:block>
+   </th>
+   <td>
+    <select tal:attributes="name python:'@group%d'%n">
+     <option value="" i18n:translate="">- nothing -</option>
+     <option tal:repeat="col context/properties"
+             tal:attributes="value col/_name;
+                             selected python:key and col._name == key[1]"
+             tal:content="col/_name"
+             i18n:translate="">column</option>
+    </select>
+   </td>
+   <th i18n:translate="">Descending:</th>
+   <td><input type="checkbox" tal:attributes="name python:'@groupdir%d'%n;
+              checked python:key and key[0] == '-'">
+   </td>
+  </tr>
+  </tal:block>
+  <tr><td colspan="4">
+              <input type="submit" value="Redisplay" i18n:attributes="value">
+              <tal:block tal:replace="structure
+                python:request.indexargs_form(sort=0, group=0)" />
+  </td></tr>
+ </table>
+</form>
+
+</tal:block>
+
+</td>
+</tal:block><tal:comment condition=false> vim: sw=1 ts=8 et si
+</tal:comment>
diff --git a/share/roundup/templates/classic/html/issue.item.html b/share/roundup/templates/classic/html/issue.item.html
new file mode 100644 (file)
index 0000000..41ee073
--- /dev/null
@@ -0,0 +1,197 @@
+<!-- dollarId: issue.item,v 1.4 2001/08/03 01:19:43 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">
+<tal:block condition="context/id" i18n:translate=""
+ >Issue <tal:x tal:content="context/id" i18n:name="id"
+ />: <tal:x content="context/title" i18n:name="title"
+ /> - <tal:x content="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:block>
+<tal:block condition="not:context/id" i18n:translate=""
+ >New Issue - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:block>
+</title>
+<tal:block metal:fill-slot="body_title">
+ <span tal:condition="python: not (context.id or context.is_edit_ok())"
+  tal:omit-tag="python:1" i18n:translate="">New Issue</span>
+ <span tal:condition="python: not context.id and context.is_edit_ok()"
+  tal:omit-tag="python:1" i18n:translate="">New Issue Editing</span>
+ <span tal:condition="python: context.id and not context.is_edit_ok()"
+  tal:omit-tag="python:1" i18n:translate="">Issue<tal:x
+  replace="context/id" i18n:name="id" /></span>
+ <span tal:condition="python: context.id and context.is_edit_ok()"
+  tal:omit-tag="python:1" i18n:translate="">Issue<tal:x
+  replace="context/id" i18n:name="id" /> Editing</span>
+</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<div tal:condition="context/is_view_ok">
+
+<form method="POST" name="itemSynopsis"
+      onSubmit="return submit_once()" enctype="multipart/form-data"
+      tal:attributes="action context/designator">
+
+<table class="form">
+<tr>
+ <th class="required" i18n:translate="">Title</th>
+ <td colspan=3 tal:content="structure python:context.title.field(size=60)">title</td>
+</tr>
+
+<tr>
+ <th class="required" i18n:translate="">Priority</th>
+ <td tal:content="structure context/priority/menu">priority</td>
+ <th i18n:translate="">Status</th>
+ <td tal:content="structure context/status/menu">status</td>
+</tr>
+
+<tr>
+ <th i18n:translate="">Superseder</th>
+ <td>
+  <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
+  <span tal:condition="context/is_edit_ok" tal:replace="structure python:db.issue.classhelp('id,title', property='superseder')" />
+  <span tal:condition="context/superseder">
+   <br><span i18n:translate="">View:</span>
+     <a tal:repeat="sup context/superseder"
+        tal:content="python:sup['id'] + ', '*(not repeat['sup'].end)"
+        tal:attributes="href string:issue${sup/id}"></a>
+  </span>
+ </td>
+ <th i18n:translate="">Nosy List</th>
+ <td>
+  <span tal:replace="structure context/nosy/field" />
+  <span tal:condition="context/is_edit_ok" tal:replace="structure
+python:db.user.classhelp('username,realname,address', property='nosy', width='600')" /><br>
+ </td>
+</tr>
+
+<tr>
+ <th i18n:translate="">Assigned To</th>
+ <td tal:content="structure context/assignedto/menu">assignedto menu</td>
+ <th i18n:translate="">Keywords</th>
+ <td>
+  <span tal:replace="structure context/keyword/field" />
+  <span tal:condition="context/is_edit_ok" tal:replace="structure python:db.keyword.classhelp(property='keyword')" />
+ </td>
+</tr>
+
+<tr tal:condition="context/is_edit_ok">
+ <th i18n:translate="">Change Note</th>
+ <td colspan=3>
+  <textarea tal:content="request/form/@note/value | default"
+            name="@note" wrap="hard" rows="5" cols="80"></textarea>
+ </td>
+</tr>
+
+<tr tal:condition="context/is_edit_ok">
+ <th i18n:translate="">File</th>
+ <td colspan=3><input type="file" name="@file" size="40"></td>
+</tr>
+
+<tr tal:condition="context/is_edit_ok">
+ <td>
+  &nbsp;
+  <input type="hidden" name="@template" value="item">
+  <input type="hidden" name="@required" value="title,priority">
+ </td>
+ <td colspan=3>
+  <span tal:replace="structure context/submit">submit button</span>
+  <a tal:condition="context/id" tal:attributes="href context/copy_url"
+   i18n:translate="">Make a copy</a>
+ </td>
+</tr>
+
+</table>
+</form>
+
+<tal:block tal:condition="not:context/id" i18n:translate="">
+<table class="form">
+<tr>
+ <td>Note:&nbsp;</td>
+ <th class="required">highlighted</th>
+ <td>&nbsp;fields are required.</td>
+</tr>
+</table>
+</tal:block>
+
+<p tal:condition="context/id" i18n:translate="">
+ Created on <b tal:content="context/creation" i18n:name="creation" />
+ by <b tal:content="context/creator" i18n:name="creator" />,
+ last changed <b content="context/activity" i18n:name="activity" />
+ by <b tal:content="context/actor" i18n:name="actor" />.
+</p>
+
+<table class="files" tal:condition="context/files">
+ <tr><th colspan="5" class="header" i18n:translate="">Files</th></tr>
+ <tr>
+  <th i18n:translate="">File name</th>
+  <th i18n:translate="">Uploaded</th>
+  <th i18n:translate="">Type</th>
+  <th i18n:translate="">Edit</th>
+  <th i18n:translate="">Remove</th>
+ </tr>
+ <tr tal:repeat="file context/files">
+  <td>
+   <a tal:attributes="href file/download_url"
+      tal:content="file/name">dld link</a>
+  </td>
+  <td>
+   <span tal:content="file/creator">creator's name</span>,
+   <span tal:content="file/creation">creation date</span>
+  </td>
+  <td tal:content="file/type" />
+  <td><a tal:condition="file/is_edit_ok"
+          tal:attributes="href string:file${file/id}">edit</a>
+  </td>
+  <td>
+   <form style="padding:0" tal:condition="context/is_edit_ok"
+         tal:attributes="action string:issue${context/id}">
+    <input type="hidden" name="@remove@files" tal:attributes="value file/id">
+    <input type="hidden" name="@action" value="edit">
+    <input type="submit" value="remove" i18n:attributes="value">
+   </form>
+  </td>
+ </tr>
+</table>
+
+<table class="messages" tal:condition="context/messages">
+ <tr><th colspan="4" class="header" i18n:translate="">Messages</th></tr>
+ <tal:block tal:repeat="msg context/messages/reverse">
+  <tr>
+   <th><a tal:attributes="href string:msg${msg/id}"
+    i18n:translate="">msg<tal:x replace="msg/id" i18n:name="id" /> (view)</a></th>
+   <th i18n:translate="">Author: <tal:x replace="msg/author"
+       i18n:name="author" /></th>
+   <th i18n:translate="">Date: <tal:x replace="msg/date"
+       i18n:name="date" /></th>
+   <th>
+    <form style="padding:0" tal:condition="context/is_edit_ok"
+          tal:attributes="action string:issue${context/id}">
+     <input type="hidden" name="@remove@messages" tal:attributes="value msg/id">
+     <input type="hidden" name="@action" value="edit">
+     <input type="submit" value="remove" i18n:attributes="value">
+    </form>
+   </th>
+  </tr>
+  <tr>
+   <td colspan="4" class="content">
+    <pre tal:content="structure msg/content/hyperlinked">content</pre>
+   </td>
+  </tr>
+ </tal:block>
+</table>
+
+<tal:block tal:condition="context/id" tal:replace="structure context/history" />
+
+</div>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/issue.search.html b/share/roundup/templates/classic/html/issue.search.html
new file mode 100644 (file)
index 0000000..cff5122
--- /dev/null
@@ -0,0 +1,234 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">Issue searching - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Issue searching</span>
+<td class="content" metal:fill-slot="content">
+
+<form method="GET" name="itemSynopsis"
+      tal:attributes="action request/classname">
+      
+<table class="form" tal:define="
+   cols python:request.columns or 'id activity title status assignedto'.split();
+   sort_on python:request.sort and request.sort[0] or nothing;
+   sort_desc python:sort_on and sort_on[0] == '-';
+   sort_on python:(sort_on and sort_on[1]) or 'activity';
+   group_on python:request.group and request.group[0] or nothing;
+   group_desc python:group_on and group_on[0] == '-';
+   group_on python:(group_on and group_on[1]) or 'priority';
+
+   search_input templates/page/macros/search_input;
+   search_date templates/page/macros/search_date;
+   column_input templates/page/macros/column_input;
+   sort_input templates/page/macros/sort_input;
+   group_input templates/page/macros/group_input;
+   search_select templates/page/macros/search_select;
+   search_select_translated templates/page/macros/search_select_translated;
+   search_multiselect templates/page/macros/search_multiselect;">
+
+<tr>
+ <th class="header">&nbsp;</th>
+ <th class="header" i18n:translate="">Filter on</th>
+ <th class="header" i18n:translate="">Display</th>
+ <th class="header" i18n:translate="">Sort on</th>
+ <th class="header" i18n:translate="">Group on</th>
+</tr>
+
+<tr tal:define="name string:@search_text">
+  <th i18n:translate="">All text*:</th>
+  <td metal:use-macro="search_input"></td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+  <td>&nbsp;</td>
+</tr>
+
+<tr tal:define="name string:title">
+  <th i18n:translate="">Title:</th>
+  <td metal:use-macro="search_input"></td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td>&nbsp;</td>
+</tr>
+
+<tr tal:define="name string:keyword;
+                db_klass string:keyword;
+                db_content string:name;">
+  <th i18n:translate="">Keyword:</th>
+  <td metal:use-macro="search_select">
+    <option metal:fill-slot="extra_options" value="-1" i18n:translate=""
+            tal:attributes="selected python:value == '-1'">not selected</option>
+  </td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td metal:use-macro="group_input"></td>
+</tr>
+
+<tr tal:define="name string:id">
+  <th i18n:translate="">ID:</th>
+  <td metal:use-macro="search_input"></td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td>&nbsp;</td>
+</tr>
+
+<tr tal:define="name string:creation">
+  <th i18n:translate="">Creation Date:</th>
+  <td metal:use-macro="search_date"></td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td metal:use-macro="group_input"></td>
+</tr>
+
+<tr tal:define="name string:creator;
+                db_klass string:user;
+                db_content string:username;"
+    tal:condition="db/user/is_view_ok">
+  <th i18n:translate="">Creator:</th>
+  <td metal:use-macro="search_select">
+    <option metal:fill-slot="extra_options" i18n:translate=""
+            tal:attributes="value request/user/id">created by me</option>
+  </td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td metal:use-macro="group_input"></td>
+</tr>
+
+<tr tal:define="name string:activity">
+  <th i18n:translate="">Activity:</th>
+  <td metal:use-macro="search_date"></td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td>&nbsp;</td>
+</tr>
+
+<tr tal:define="name string:actor;
+                db_klass string:user;
+                db_content string:username;"
+    tal:condition="db/user/is_view_ok">
+  <th i18n:translate="">Actor:</th>
+  <td metal:use-macro="search_select">
+    <option metal:fill-slot="extra_options" i18n:translate=""
+            tal:attributes="value request/user/id">done by me</option>
+  </td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td>&nbsp;</td>
+</tr>
+
+<tr tal:define="name string:priority;
+                db_klass string:priority;
+                db_content string:name;">
+  <th i18n:translate="">Priority:</th>
+  <td metal:use-macro="search_select_translated">
+    <option metal:fill-slot="extra_options" value="-1" i18n:translate=""
+            tal:attributes="selected python:value == '-1'">not selected</option>
+  </td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td metal:use-macro="group_input"></td>
+</tr>
+
+<tr tal:define="name string:status;
+                db_klass string:status;
+                db_content string:name;">
+  <th i18n:translate="">Status:</th>
+  <td metal:use-macro="search_select_translated">
+    <tal:block metal:fill-slot="extra_options">
+      <option value="-1,1,2,3,4,5,6,7" i18n:translate=""
+              tal:attributes="selected python:value == '-1,1,2,3,4,5,6,7'">not resolved</option>
+      <option value="-1" i18n:translate=""
+              tal:attributes="selected python:value == '-1'">not selected</option>
+    </tal:block>
+  </td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td metal:use-macro="group_input"></td>
+</tr>
+
+<tr tal:define="name string:assignedto;
+                db_klass string:user;
+                db_content string:username;"
+    tal:condition="db/user/is_view_ok">
+  <th i18n:translate="">Assigned to:</th>
+  <td metal:use-macro="search_select">
+    <tal:block metal:fill-slot="extra_options">
+      <option tal:attributes="value request/user/id"
+       i18n:translate="">assigned to me</option>
+      <option value="-1" tal:attributes="selected python:value == '-1'"
+       i18n:translate="">unassigned</option>
+    </tal:block>
+  </td>
+  <td metal:use-macro="column_input"></td>
+  <td metal:use-macro="sort_input"></td>
+  <td metal:use-macro="group_input"></td>
+</tr>
+
+<tr>
+ <th i18n:translate="">No Sort or group:</th>
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ <td><input type="radio" name="@sort" value=""></td>
+ <td><input type="radio" name="@group" value=""></td>
+</tr>
+
+<tr>
+<th i18n:translate="">Pagesize:</th>
+<td><input name="@pagesize" size="3" value="50"
+           tal:attributes="value request/form/@pagesize/value | default"></td>
+</tr>
+
+<tr>
+<th i18n:translate="">Start With:</th>
+<td><input name="@startwith" size="3" value="0"
+           tal:attributes="value request/form/@startwith/value | default"></td>
+</tr>
+
+<tr>
+<th i18n:translate="">Sort Descending:</th>
+<td><input type="checkbox" name="@sortdir"
+           tal:attributes="checked sort_desc">
+</td>
+</tr>
+
+<tr>
+<th i18n:translate="">Group Descending:</th>
+<td><input type="checkbox" name="@groupdir"
+           tal:attributes="checked group_desc">
+</td>
+</tr>
+
+<tr tal:condition="python:request.user.hasPermission('Edit', 'query')">
+ <th i18n:translate="">Query name**:</th>
+ <td tal:define="value request/form/@queryname/value | nothing">
+  <input name="@queryname" tal:attributes="value value">
+  <input type="hidden" name="@old-queryname" tal:attributes="value value">
+ </td>
+</tr>
+
+<tr>
+  <td>
+   &nbsp;
+   <input type="hidden" name="@action" value="search">
+  </td>
+  <td><input type="submit" value="Search" i18n:attributes="value"></td>
+</tr>
+
+<tr><td>&nbsp;</td>
+ <td colspan="4" class="help">
+  <span i18n:translate="" tal:omit-tag="true">
+   *: The "all text" field will look in message bodies and issue titles
+  </span><br>
+  <span tal:condition="python:request.user.hasPermission('Edit', 'query')"
+   i18n:translate="" tal:omit-tag="true"
+  >
+   **: If you supply a name, the query will be saved off and available as a
+       link in the sidebar
+  </span>
+ </td>
+</tr>
+</table>
+
+</form>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/keyword.item.html b/share/roundup/templates/classic/html/keyword.item.html
new file mode 100644 (file)
index 0000000..cf1e26a
--- /dev/null
@@ -0,0 +1,55 @@
+<!-- dollarId: keyword.item,v 1.3 2002/05/22 00:32:34 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">Keyword editing - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Keyword editing</span>
+<td class="content" metal:fill-slot="content">
+
+<table class="otherinfo" tal:define="keywords db/keyword/list"
+       tal:condition="keywords">
+ <tr><th colspan="4" class="header" i18n:translate="">Existing Keywords</th></tr>
+ <tr tal:repeat="start python:range(0, len(keywords), 4)">
+  <td width="25%" tal:define="batch python:utils.Batch(keywords, 4, start)"
+      tal:repeat="keyword batch">
+    <a tal:attributes="href string:keyword${keyword/id}"
+       tal:content="keyword/name">keyword here</a>
+  </td>
+ </tr>
+ <tr>
+  <td colspan="4" style="border-top: 1px solid gray" i18n:translate="">
+   To edit an existing keyword (for spelling or typing errors),
+   click on its entry above.
+  </td>
+ </tr>
+</table>
+
+<p class="help" tal:condition="not:context/id" i18n:translate="">
+ To create a new keyword, enter it below and click "Submit New Entry".
+</p>
+
+<form method="POST" onSubmit="return submit_once()"
+      enctype="multipart/form-data"
+      tal:attributes="action context/designator">
+
+ <table class="form">
+  <tr>
+   <th i18n:translate="">Keyword</th>
+   <td tal:content="structure context/name/field">name</td>
+  </tr>
+
+  <tr>
+   <td>
+    &nbsp;
+    <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
+   </td>
+  </tr>
+ </table>
+</form>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/msg.index.html b/share/roundup/templates/classic/html/msg.index.html
new file mode 100644 (file)
index 0000000..02405dc
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ >List of messages - <span tal:replace="config/TRACKER_NAME"
+ i18n:name="tracker"/></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Message listing</span>
+<td class="content" metal:fill-slot="content">
+<table tal:define="batch request/batch" class="messages">
+ <tr><th colspan=2 class="header" i18n:translate="">Messages</th></tr>
+ <tal:block tal:repeat="msg batch">
+  <tr>
+   <th tal:content="string:Author: ${msg/author}">author</th>
+   <th tal:content="string:Date: ${msg/date}">date</th>
+  </tr>
+  <tr>
+   <td colspan="2"><pre tal:content="msg/content">content</pre></td>
+  </tr>
+ </tal:block>
+
+ <metal:block use-macro="templates/issue.index/macros/batch-footer" />
+
+</table>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/msg.item.html b/share/roundup/templates/classic/html/msg.item.html
new file mode 100644 (file)
index 0000000..e755174
--- /dev/null
@@ -0,0 +1,83 @@
+<!-- dollarId: msg.item,v 1.3 2002/05/22 00:32:34 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">
+<tal:block condition="context/id" i18n:translate=""
+ >Message <span tal:replace="context/id" i18n:name="id"
+ /> - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:block>
+<tal:block condition="not:context/id" i18n:translate=""
+ >New Message - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:block>
+</title>
+<tal:block metal:fill-slot="body_title">
+ <span tal:condition="python: not (context.id or context.is_edit_ok())"
+  tal:omit-tag="python:1" i18n:translate="">New Message</span>
+ <span tal:condition="python: not context.id and context.is_edit_ok()"
+  tal:omit-tag="python:1" i18n:translate="">New Message Editing</span>
+ <span tal:condition="python: context.id and not context.is_edit_ok()"
+  tal:omit-tag="python:1" i18n:translate="">Message<tal:x
+  replace="context/id" i18n:name="id" /></span>
+ <span tal:condition="python: context.id and context.is_edit_ok()"
+  tal:omit-tag="python:1" i18n:translate="">Message<tal:x
+  replace="context/id" i18n:name="id" /> Editing</span>
+</tal:block>
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<div tal:condition="context/is_view_ok">
+<table class="form">
+
+<tr>
+ <th i18n:translate="">Author</th>
+ <td tal:content="context/author"></td>
+</tr>
+
+<tr>
+ <th i18n:translate="">Recipients</th>
+ <td tal:content="context/recipients"></td>
+</tr>
+
+<tr>
+ <th i18n:translate="">Date</th>
+ <td tal:content="context/date"></td>
+</tr>
+</table>
+
+<table class="messages">
+ <tr><th colspan=2 class="header" i18n:translate="">Content</th></tr>
+ <tr>
+  <td class="content" colspan=2><pre tal:content="structure context/content/hyperlinked"></pre></td>
+ </tr>
+</table>
+
+<table class="files" tal:condition="context/files">
+ <tr><th colspan="2" class="header" i18n:translate="">Files</th></tr>
+ <tr>
+  <th i18n:translate="">File name</th>
+  <th i18n:translate="">Uploaded</th>
+ </tr>
+ <tr tal:repeat="file context/files">
+  <td>
+   <a tal:attributes="href string:file${file/id}/${file/name}"
+      tal:content="file/name">dld link</a>
+  </td>
+  <td>
+   <span tal:content="file/creator">creator's name</span>,
+   <span tal:content="file/creation">creation date</span>
+  </td>
+ </tr>
+</table>
+
+<tal:block tal:replace="structure context/history" />
+
+</div>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/page.html b/share/roundup/templates/classic/html/page.html
new file mode 100644 (file)
index 0000000..cd64875
--- /dev/null
@@ -0,0 +1,347 @@
+<!-- vim:sw=2 sts=2
+--><tal:block metal:define-macro="icing"
+><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title metal:define-slot="head_title">title goes here</title>
+<link rel="stylesheet" type="text/css" href="@@file/style.css">
+<meta http-equiv="Content-Type"
+ tal:attributes="content string:text/html;; charset=${request/client/charset}" />
+<script tal:replace="structure request/base_javascript">
+</script>
+<metal:x define-slot="more-javascript" />
+
+</head>
+<body class="body">
+
+<table class="body"
+ tal:define="
+kw_edit python:request.user.hasPermission('Edit', 'keyword');
+kw_create python:request.user.hasPermission('Create', 'keyword');
+kw_edit_link python:kw_edit and db.keyword.list();
+columns string:id,activity,title,creator,status;
+columns_showall string:id,activity,title,creator,assignedto,status;
+status_notresolved string:-1,1,2,3,4,5,6,7;
+"
+>
+
+<tr>
+ <td class="page-header-left">&nbsp;</td>
+ <td class="page-header-top">
+   <div id="body-title">
+     <h2><span metal:define-slot="body_title">body title</span></h2>
+   </div>
+   <div id="searchbox">
+     <form method="GET" action="issue">
+       <input type="hidden" name="@columns"
+             tal:attributes="value columns_showall"
+             value="id,activity,title,creator,assignedto,status"/>
+       <input type="hidden" name="@sort" value="activity"/>
+       <input type="hidden" name="@group" value="priority"/>
+       <input id="search-text" name="@search_text" size="10"
+              tal:attributes="value request/search_text | default" />
+       <input type="submit" id="submit" name="submit" value="Search"
+              i18n:attributes="value" />
+     </form>
+  </div>
+ </td>
+</tr>
+
+<tr>
+ <td rowspan="2" valign="top" class="sidebar">
+  <p class="classblock"
+     tal:condition="python:request.user.hasPermission('View', 'query')">
+   <span i18n:translate=""
+    ><b>Your Queries</b> (<a href="query?@template=edit">edit</a>)</span><br>
+   <tal:block tal:repeat="qs request/user/queries">
+    <a href="#" tal:attributes="href string:${qs/klass}?${qs/url}&@dispname=${qs/name}"
+       tal:content="qs/name">link</a><br>
+   </tal:block>
+  </p>
+
+  <form method="POST" tal:attributes="action request/base">
+   <p class="classblock"
+       tal:condition="python:request.user.hasPermission('View', 'issue')">
+    <b i18n:translate="">Issues</b><br>
+    <span tal:condition="python:request.user.hasPermission('Create', 'issue')">
+      <a href="issue?@template=item" i18n:translate="">Create New</a><br>
+    </span>
+    <a href="#"
+       tal:attributes="href python:request.indexargs_url('issue', {
+      '@sort': '-activity',
+      '@group': 'priority',
+      '@filter': 'status,assignedto',
+      '@columns': columns,
+      '@search_text': '',
+      'status': status_notresolved,
+      'assignedto': '-1',
+      '@dispname': i18n.gettext('Show Unassigned'),
+     })"
+       i18n:translate="">Show Unassigned</a><br>
+    <a href="#"
+       tal:attributes="href python:request.indexargs_url('issue', {
+      '@sort': '-activity',
+      '@group': 'priority',
+      '@filter': 'status',
+      '@columns': columns_showall,
+      '@search_text': '',
+      'status': status_notresolved,
+      '@dispname': i18n.gettext('Show All'),
+     })"
+       i18n:translate="">Show All</a><br>
+    <a href="issue?@template=search" i18n:translate="">Search</a><br>
+    <input type="submit" class="form-small" value="Show issue:"
+     i18n:attributes="value"><input class="form-small" size="4"
+     type="text" name="@number">
+    <input type="hidden" name="@type" value="issue">
+    <input type="hidden" name="@action" value="show">
+   </p>
+  </form>
+
+  <p class="classblock"
+     tal:condition="python:kw_edit or kw_create">
+   <b i18n:translate="">Keywords</b><br>
+   <span tal:condition="python:request.user.hasPermission('Create', 'keyword')">
+    <a href="keyword?@template=item" i18n:translate="">Create New</a><br>
+   </span>
+   <span tal:condition="kw_edit_link">
+    <a href="keyword?@template=item" i18n:translate="">Edit Existing</a><br>
+   </span>
+  </p>
+
+  <p class="classblock"
+       tal:condition="python:request.user.hasPermission('View', 'user')">
+   <b i18n:translate="">Administration</b><br>
+   <span tal:condition="python:request.user.hasPermission('Edit', None)">
+    <a href="home?@template=classlist" i18n:translate="">Class List</a><br>
+   </span>
+   <span tal:condition="python:request.user.hasPermission('View', 'user')
+                            or request.user.hasPermission('Edit', 'user')">
+    <a href="user"  i18n:translate="">User List</a><br>
+   </span>
+   <a tal:condition="python:request.user.hasPermission('Create', 'user')"
+      href="user?@template=item" i18n:translate="">Add User</a>
+  </p>
+
+  <form method="POST" tal:condition="python:request.user.username=='anonymous'"
+        tal:attributes="action request/base">
+   <p class="userblock">
+    <b i18n:translate="">Login</b><br>
+    <input size="10" name="__login_name"><br>
+    <input size="10" type="password" name="__login_password"><br>
+    <input type="hidden" name="@action" value="Login">
+    <input type="checkbox" name="remember" id="remember">
+    <label for="remember" i18n:translate="">Remember me?</label><br>
+    <input type="submit" value="Login" i18n:attributes="value"><br>
+    <input type="hidden" name="__came_from" tal:attributes="value string:${request/base}${request/env/PATH_INFO}">
+    <span tal:replace="structure request/indexargs_form" />
+    <a href="user?@template=register"
+       tal:condition="python:request.user.hasPermission('Create', 'user')"
+     i18n:translate="">Register</a><br>
+    <a href="user?@template=forgotten" i18n:translate="">Lost&nbsp;your&nbsp;login?</a><br>
+   </p>
+  </form>
+
+  <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
+   <b i18n:translate="">Hello, <span i18n:name="user"
+    tal:replace="python:request.user.username.plain(escape=1)">username</span></b><br>
+    <a href="#"
+       tal:attributes="href python:request.indexargs_url('issue', {
+      '@sort': '-activity',
+      '@group': 'priority',
+      '@filter': 'status,assignedto',
+      '@columns': 'id,activity,title,creator,status',
+      '@search_text': '',
+      'status': status_notresolved,
+      'assignedto': request.user.id,
+      '@dispname': i18n.gettext('Your Issues'),
+     })"
+    i18n:translate="">Your Issues</a><br>
+   <a href="#" tal:attributes="href string:user${request/user/id}"
+    i18n:translate="">Your Details</a><br>
+   <a href="#" tal:attributes="href python:request.indexargs_url('',
+       {'@action':'logout'})" i18n:translate="">Logout</a>
+  </p>
+  <p class="userblock">
+   <b i18n:translate="">Help</b><br>
+   <a href="http://roundup.sourceforge.net/doc-1.0/"
+    i18n:translate="">Roundup docs</a>
+  </p>
+ </td>
+ <td>
+  <p tal:condition="options/error_message | nothing" class="error-message"
+     tal:repeat="m options/error_message" tal:content="structure m" />
+  <p tal:condition="options/ok_message | nothing" class="ok-message">
+    <span tal:repeat="m options/ok_message"
+       tal:content="structure string:$m <br/ > " />
+     <a class="form-small" tal:attributes="href request/current_url"
+        i18n:translate="">clear this message</a>
+  </p>
+ </td>
+</tr>
+<tr>
+ <td class="content" metal:define-slot="content">Page content goes here</td>
+</tr>
+
+</table>
+
+<pre tal:condition="request/form/debug | nothing" tal:content="request">
+</pre>
+
+</body>
+</html>
+</tal:block>
+
+<!--
+The following macros are intended to be used in search pages.
+
+The invoking context must define a "name" variable which names the
+property being searched.
+
+See issue.search.html in the classic template for examples.
+-->
+
+<!-- creates a th and a label: -->
+<th metal:define-macro="th_label"
+    tal:define="required required | python:[]"
+    tal:attributes="class python:(name in required) and 'required' or nothing">
+  <label tal:attributes="for name" tal:content="label" i18n:translate="">text</label>
+       <metal:x define-slot="behind_the_label" />
+</th>
+
+<td metal:define-macro="search_input">
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+</td>
+
+<td metal:define-macro="search_date">
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+  <a class="classhelp"
+        tal:attributes="href python:'''javascript:help_window('issue?@template=calendar&property=%s&form=itemSynopsis', 300, 200)'''%name">(cal)</a>
+</td>
+
+<td metal:define-macro="search_popup">
+  <!--
+    context needs to specify the popup "columns" as a comma-separated
+    string (eg. "id,title" or "id,name,description") as well as name
+  -->
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+  <span tal:replace="structure python:db.issue.classhelp(columns,
+                                      property=name)" />
+</td>
+
+<td metal:define-macro="search_select">
+  <select tal:attributes="name name; id name"
+          tal:define="value python:request.form.getvalue(name)">
+    <option value="" i18n:translate="">don't care</option>
+    <metal:slot define-slot="extra_options" />
+    <option value="" i18n:translate="" disabled="disabled">------------</option>
+    <option tal:repeat="s python:db[db_klass].list()"
+            tal:attributes="value s/id; selected python:value == s.id"
+            tal:content="python:s[db_content]"></option>
+  </select>
+</td>
+
+<!-- like search_select, but translates the further values.
+Could extend it (METAL 1.1 attribute "extend-macro")
+-->
+<td metal:define-macro="search_select_translated">
+  <select tal:attributes="name name; id name"
+          tal:define="value python:request.form.getvalue(name)">
+    <option value="" i18n:translate="">don't care</option>
+    <metal:slot define-slot="extra_options" />
+    <option value="" i18n:translate="" disabled="disabled">------------</option>
+    <option tal:repeat="s python:db[db_klass].list()"
+            tal:attributes="value s/id; selected python:value == s.id"
+                                               tal:content="python:s[db_content]"
+                                               i18n:translate=""></option>
+  </select>
+</td>
+
+<!-- currently, there is no convenient API to get a list of all roles -->
+<td metal:define-macro="search_select_roles"
+         tal:define="onchange onchange | nothing">
+  <select name=roles id=roles tal:attributes="onchange onchange">
+    <option value="" i18n:translate="">don't care</option>
+    <option value="" i18n:translate="" disabled="disabled">------------</option>
+    <option value="User">User</option>
+    <option value="Admin">Admin</option>
+    <option value="Anonymous">Anonymous</option>
+  </select>
+</td>
+
+<td metal:define-macro="search_multiselect">
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+  <span tal:replace="structure python:db[db_klass].classhelp(db_content,
+                                        property=name, width='600')" />
+</td>
+
+<td metal:define-macro="search_checkboxes">
+ <ul class="search-checkboxes"
+     tal:define="value python:request.form.getvalue(name);
+                 values python:value and value.split(',') or []">
+ <li tal:repeat="s python:db[db_klass].list()">
+  <input type="checkbox" tal:attributes="name name; id string:$name-${s/id};
+    value s/id; checked python:s.id in values" />
+  <label tal:attributes="for string:$name-${s/id}"
+         tal:content="python:s[db_content]" />
+ </li>
+ <li metal:define-slot="no_value_item">
+  <input type="checkbox" value="-1" tal:attributes="name name;
+     id string:$name--1; checked python:value == '-1'" />
+  <label tal:attributes="for string:$name--1" i18n:translate="">no value</label>
+ </li>
+ </ul>
+</td>
+
+<td metal:define-macro="column_input">
+  <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"
+         tal:attributes="value name;
+                         checked python:name == sort_on">
+</td>
+
+<td metal:define-macro="group_input">
+  <input type="radio" name="@group"
+         tal:attributes="value name;
+                         checked python:name == group_on">
+</td>
+
+<!--
+The following macros are intended for user editing.
+
+The invoking context must define a "name" variable which names the
+property being searched; the "edit_ok" variable tells whether the
+current user is allowed to edit.
+
+See user.item.html in the classic template for examples.
+-->
+<script metal:define-macro="user_utils" type="text/javascript" src="@@file/user_utils.js"></script>
+
+<!-- src: value will be re-used for other input fields -->
+<input metal:define-macro="user_src_input"
+    type="text" tal:attributes="onblur python:edit_ok and 'split_name(this)';
+    id name; name name; value value; readonly not:edit_ok"
+    value="heinz.kunz">
+<!-- normal: no re-using -->
+<input metal:define-macro="user_normal_input" type="text"
+    tal:attributes="id name; name name; value value; readonly not:edit_ok"
+    value="heinz">
+<!-- password: type; no initial value -->
+    <input metal:define-macro="user_pw_input" type="password"
+    tal:attributes="id name; name name; readonly not:edit_ok" value="">
+    <input metal:define-macro="user_confirm_input" type="password"
+    tal:attributes="id name; name string:@confirm@$name; readonly not:edit_ok" value="">
+
diff --git a/share/roundup/templates/classic/html/query.edit.html b/share/roundup/templates/classic/html/query.edit.html
new file mode 100644 (file)
index 0000000..2c586f1
--- /dev/null
@@ -0,0 +1,111 @@
+<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ >"Your Queries" Editing - <span tal:replace="config/TRACKER_NAME"
+ i18n:name="tracker" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">"Your Queries" Editing</span>
+
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="not:context/is_edit_ok"
+ i18n:translate="">You are not allowed to edit queries.</span>
+
+<script language="javascript">
+// This exists solely because I can't figure how to get the & into an
+// attributes TALES expression, and so it keeps getting quoted.
+function retire(qid) {
+    window.location = 'query'+qid+'?@action=retire&@template=edit';
+}
+</script>
+
+<form method="POST" onSubmit="return submit_once()" action="query"
+      enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<table class="list" width="100%"
+       tal:define="uid request/user/id; mine request/user/queries">
+
+<tr><th i18n:translate="">Query</th>
+    <th i18n:translate="">Include in "Your Queries"</th>
+    <th i18n:translate="">Edit</th>
+    <th i18n:translate="">Private to you?</th>
+    <th>&nbsp;</th>
+</tr>
+
+<tr tal:repeat="query mine">
+ <tal:block condition="query/is_retired">
+
+ <td><a tal:attributes="href string:${query/klass}?${query/url}"
+        tal:content="query/name">query</a></td>
+
+ <td metal:define-macro="include">
+  <select tal:condition="python:query.id not in mine"
+          tal:attributes="name string:user${uid}@add@queries">
+    <option value="" i18n:translate="">leave out</option>
+    <option tal:attributes="value query/id" i18n:translate="">include</option>
+  </select>
+  <select tal:condition="python:query.id in mine"
+          tal:attributes="name string:user${uid}@remove@queries">
+    <option value="" i18n:translate="">leave in</option>
+    <option tal:attributes="value query/id" i18n:translate="">remove</option>
+  </select>
+ </td>
+
+ <td colspan="3" i18n:translate="">[query is retired]</td>
+
+ <!-- <td> maybe offer "restore" some day </td> -->
+ </tal:block>
+</tr>
+
+<tr tal:repeat="query mine">
+ <tal:block condition="not:query/is_retired">
+ <td><a tal:attributes="href string:${query/klass}?${query/url}"
+        tal:content="query/name">query</a></td>
+
+ <td metal:use-macro="template/macros/include" />
+
+ <td><a tal:attributes="href string:query${query/id}" i18n:translate="">edit</a></td>
+
+ <td>
+  <select tal:attributes="name string:query${query/id}@private_for">
+   <option tal:attributes="selected python:query.private_for == uid;
+           value uid" i18n:translate="">yes</option>
+   <option tal:attributes="selected python:query.private_for == None"
+           value="-1" i18n:translate="">no</option>
+  </select>
+ </td>
+
+ <td>
+  <input type="button" value="Delete" i18n:attributes="value"
+  tal:attributes="onClick python:'''retire('%s')'''%query.id">
+  </td>
+  </tal:block>
+</tr>
+
+<tr tal:define="queries python:db.query.filter(filterspec={'private_for':None})"
+     tal:repeat="query queries">
+ <tal:block condition="python: query.creator != uid">
+ <td><a tal:attributes="href string:${query/klass}?${query/url}"
+        tal:content="query/name">query</a></td>
+
+ <td metal:use-macro="template/macros/include" />
+
+ <td colspan="3" tal:condition="query/is_edit_ok">
+  <a tal:attributes="href string:query${query/id}" i18n:translate="">edit</a>
+ </td>
+ <td tal:condition="not:query/is_edit_ok" colspan="3"
+    i18n:translate="">[not yours to edit]</td>
+ </tal:block>
+</tr>
+
+<tr><td colspan="5">
+   <input type="hidden" name="@action" value="edit">
+   <input type="hidden" name="@template" value="edit">
+   <input type="submit" value="Save Selection" i18n:attributes="value">
+</td></tr>
+
+</table>
+
+</form>
+</td>
+</tal:block>
diff --git a/share/roundup/templates/classic/html/query.item.html b/share/roundup/templates/classic/html/query.item.html
new file mode 100644 (file)
index 0000000..453e13d
--- /dev/null
@@ -0,0 +1,3 @@
+<!-- query.item -->
+<span tal:replace="structure context/renderQueryForm" />
+
diff --git a/share/roundup/templates/classic/html/style.css b/share/roundup/templates/classic/html/style.css
new file mode 100644 (file)
index 0000000..72e7ffc
--- /dev/null
@@ -0,0 +1,433 @@
+/* main page styles */
+body.body {
+  font-family: sans-serif, Arial, Helvetica;
+  background-color: white;
+  color: #333;
+  margin: 0;
+}
+a[href]:hover {
+  color:blue;
+  text-decoration: underline;
+}
+a[href], a[href]:link {
+  color:blue;
+  text-decoration: none;
+}
+
+table.body {
+  border: 0;
+  padding: 0;
+  border-spacing: 0;
+  border-collapse: separate;
+}
+
+td.page-header-left {
+  padding: 5px;
+  border-bottom: 1px solid #444;
+}
+td.sidebar {
+  padding: 1px 0 0 1px;
+  white-space: nowrap;
+}
+
+/* don't display the sidebar when printing */
+@media print {
+    td.page-header-left {
+        display: none;
+    }
+    td.sidebar {
+        display: none;
+    }
+    .index-controls {
+        display: none;
+    }
+    #searchbox {
+        display: none;
+    }
+}
+
+td.page-header-top {
+  padding: 5px;
+  border-bottom: 1px solid #444;
+}
+#searchbox {
+    float: right;
+}
+
+div#body-title {
+  float: left;
+}
+
+
+div#searchbox {
+  float: right;
+  padding-top: 1em;
+}
+
+div#searchbox input#search-text {
+  width: 10em;
+}
+
+form {
+  margin: 0;
+}
+
+textarea {
+    font-family: monospace;
+}
+
+td.sidebar p.classblock {
+  padding: 2px 5px 2px 5px;
+  margin: 1px;
+  border: 1px solid #444;
+  background-color: #eee;
+}
+
+td.sidebar p.userblock {
+  padding: 2px 5px 2px 5px;
+  margin: 1px 1px 1px 1px;
+  border: 1px solid #444;
+  background-color: #eef;
+}
+
+.form-small {
+  padding: 0;
+  font-size: 75%;
+}
+
+
+td.content {
+  padding: 1px 5px 1px 5px;
+  vertical-align: top;
+  width: 100%;
+}
+
+td.date, th.date { 
+  white-space: nowrap;
+}
+
+p.ok-message {
+  background-color: #22bb22;
+  padding: 5px;
+  color: white;
+  font-weight: bold;
+}
+p.error-message {
+  background-color: #bb2222;
+  padding: 5px;
+  color: white;
+  font-weight: bold;
+}
+p.error-message a[href] {
+  color: white;
+  text-decoration: underline;
+}
+
+
+/* style for search forms */
+ul.search-checkboxes {
+    display: inline;
+    padding: 0;
+    list-style: none;
+}
+ul.search-checkboxes > li {
+    display: inline;
+    padding-right: .5em;
+}
+
+
+/* style for forms */
+table.form {
+  padding: 2px;
+  border-spacing: 0;
+  border-collapse: separate;
+}
+
+table.form th {
+  color: #338;
+  text-align: right;
+  vertical-align: top;
+  font-weight: normal;
+  white-space: nowrap;
+}
+
+table.form th.header {
+  font-weight: bold;
+  background-color: #eef;
+  text-align: left;
+}
+
+table.form th.required {
+  font-weight: bold;
+}
+
+table.form td {
+  color: #333;
+  empty-cells: show;
+  vertical-align: top;
+}
+
+table.form td.optional {
+  font-weight: bold;
+  font-style: italic;
+}
+
+table.form td.html {
+  color: #777;
+}
+
+/* style for lists */
+table.list {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.list th {
+  padding: 0 4px 0 4px;
+  color: #404070;
+  background-color: #eef;
+  border: 1px solid white;
+  vertical-align: top;
+  empty-cells: show;
+}
+table.list th a[href]:hover { color: #404070 }
+table.list th a[href]:link { color: #404070 }
+table.list th a[href] { color: #404070 }
+table.list th.group {
+  background-color: #f4f4ff;
+  text-align: center;
+}
+
+table.list td {
+  padding: 0 4px 0 4px;
+  border: 1px solid white;
+  color: #404070;
+  background-color: #efefef;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+table.list tr.navigation th {
+  width: 33%;
+  border-style: hidden;
+  text-align: center;
+}
+table.list tr.navigation td {
+    border: none
+}
+table.list tr.navigation th:first-child {
+  text-align: left;
+}
+table.list tr.navigation th:last-child {
+  text-align: right;
+}
+
+
+/* style for message displays */
+table.messages {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.messages th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.messages th {
+  font-weight: bold;
+  color: black;
+  text-align: left;
+  border-bottom: 1px solid #afafaf;
+}
+
+table.messages td {
+  font-family: monospace;
+  background-color: #efefef;
+  border-bottom: 1px solid #afafaf;
+  color: black;
+  empty-cells: show;
+  border-right: 1px solid #afafaf;
+  vertical-align: top;
+  padding: 2px 5px 2px 5px;
+}
+
+table.messages td:first-child {
+  border-left: 1px solid #afafaf;
+  border-right: 1px solid #afafaf;
+}
+
+/* style for file displays */
+table.files {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.files th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.files th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+
+table.files td {
+  font-family: monospace;
+  empty-cells: show;
+}
+
+/* style for history displays */
+table.history {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.history th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+  font-size: 100%;
+}
+
+table.history th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+  font-size: 90%;
+}
+
+table.history td {
+  font-size: 90%;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+
+/* style for class list */
+table.classlist {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.classlist th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.classlist th {
+  font-weight: bold;
+  text-align: left;
+}
+
+
+/* style for class help display */
+table.classhelp {      /* the table-layout: fixed;        */ 
+  table-layout: fixed; /* compromises quality for speed   */
+  overflow: hidden;
+  font-size: .9em;
+  padding-bottom: 3em;
+}
+
+table.classhelp th {
+  font-weight: normal;
+  text-align: left;
+  color: #444;
+  background-color: #efefef;
+  border-bottom: 1px solid #afafaf;
+  border-top: 1px solid #afafaf;
+  text-transform: uppercase;
+  vertical-align: middle;
+  line-height:1.5em;
+}
+
+table.classhelp td {
+  vertical-align: middle;
+  padding-right: .2em;
+  border-bottom: 1px solid #efefef;
+  text-align: left;
+  empty-cells: show;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+
+table.classhelp tr:hover {
+  background-color: #eee;
+}
+
+label.classhelp-label {
+  cursor: pointer;
+}
+
+#classhelp-controls {
+  position: fixed;
+  display: block;
+  top: auto;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: .5em;
+  border-top: 2px solid #444;
+  background-color: #eee;
+}
+
+#classhelp-controls input.apply {
+  width: 7em;
+  font-weight: bold;
+  margin-right: 2em;
+  margin-left: 2em;
+}
+
+#classhelp-controls input.preview {
+   margin-right: 3em;
+   margin-left: 1em;
+}
+
+/* style for "other" displays */
+table.otherinfo {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.otherinfo th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.otherinfo th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+input[type="text"]:focus,
+input[type="checkbox"]:focus,
+input[type="radio"]:focus,
+input[type="password"]:focus,
+textarea:focus, select:focus {
+  background-color: #ffffc0;
+}
+
+/* vim: sts=2 sw=2 et
+*/
diff --git a/share/roundup/templates/classic/html/user.forgotten.html b/share/roundup/templates/classic/html/user.forgotten.html
new file mode 100644 (file)
index 0000000..3f0a472
--- /dev/null
@@ -0,0 +1,43 @@
+<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">Password reset request - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Password reset request</span>
+<td class="content" metal:fill-slot="content">
+
+<p i18n:translate="">You have two options if you have forgotten your password.
+If you know the email address you registered with, enter it below.</p>
+
+<form method="POST" onSubmit="return submit_once()"
+      tal:attributes="action context/designator">
+    <table class="form">
+      <tr>
+        <th i18n:translate="">Email Address:</th>
+        <td><input name="address"></td>
+      </tr>
+      <tr>
+        <td>&nbsp;</td>
+        <td>
+          <input type="hidden" name="@action" value="passrst">
+          <input type="hidden" name="@template" value="forgotten">
+          <input type="submit" value="Request password reset"
+           i18n:attributes="value">
+        </td>
+      </tr>
+</table>
+
+<p i18n:translate="">Or, if you know your username, then enter it below.</p>
+
+<table class="form">
+ <tr><th i18n:translate="">Username:</th> <td><input name="username"></td> </tr>
+ <tr><td></td><td><input type="submit" value="Request password reset"
+   i18n:attributes="value"></td></tr>
+</table>
+</form>
+
+<p i18n:translate="">A confirmation email will be sent to you -
+please follow the instructions within it to complete the reset process.</p>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/user.help-search.html b/share/roundup/templates/classic/html/user.help-search.html
new file mode 100644 (file)
index 0000000..8436897
--- /dev/null
@@ -0,0 +1,85 @@
+<html
+  tal:define="form request/form/form/value;
+  field request/form/property/value"
+  >
+  <head>
+    <title>Search input for user helper</title>
+    <script language="Javascript" type="text/javascript"
+        tal:content="structure string:<!--
+        // this is the name of the field in the original form that we're working on
+        form  = parent.opener.document.${form};
+        field  = '${field}';
+        //-->">
+    </script>
+    <script type="text/javascript" src="@@file/help_controls.js"></script>
+    <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+  </head>
+  <body onload="parent.submit.url='...'"
+    tal:define="
+qs request/env/QUERY_STRING;
+qs python:'&'.join([a for a in qs.split('&') if not a.startswith('@template=')])"
+>
+    <pre tal:content="request/env/QUERY_STRING" tal:condition=false />
+    <form method="GET" name="itemSynopsis"
+      target="list"
+      tal:attributes="action request/classname"
+      tal:define="
+      property request/form/property/value;
+   cols python:request.columns or 'id username address realname roles'.split();
+   sort_on request/sort | nothing;
+   sort_desc python:sort_on and request.sort[0][0] == '-';
+   sort_on python:sort_on and request.sort[0][1] or 'lastname';
+
+   search_input templates/page/macros/search_input;
+   search_select templates/page/macros/search_select;
+   search_select_roles templates/page/macros/search_select_roles;
+   required python:[];
+   th_label templates/page/macros/th_label;
+   ">
+   <input type="hidden" name="@template" value="help-list">
+   <input type="hidden" name="property" value="" tal:attributes="value property">
+   <input type="hidden" name="form" value="" tal:attributes="value request/form/form/value">
+   <table>
+<tr tal:define="name string:username; label string:Username:">
+  <th metal:use-macro="th_label">Name</th>
+  <td metal:use-macro="search_input"><input type=text></td>
+</tr>
+
+<tr tal:define="name string:phone; label string:Phone number">
+  <th metal:use-macro="th_label">Phone</th>
+  <td metal:use-macro="search_input"><input type=text></td>
+</tr>
+
+<tr tal:define="name string:roles;
+                onchange string:this.form.submit();
+                label string:Roles:"
+                >
+  <th metal:use-macro="th_label">role</th>
+  <td metal:use-macro="search_select_roles">
+    <select>
+      <option value="">jokester</option>
+    </select>
+  </td>
+</tr>
+
+<tr>
+  <td>&nbsp;</td>
+  <td>
+    <input type="hidden" name="@action" value="search">
+    <input type="submit" value="Search" i18n:attributes="value">
+    <input type="reset">
+    <input type="hidden" value="username,realname,phone,organisation,roles" name="properties">
+    <input type="text" name="@pagesize" id="sp-pagesize" value="25" size="2">
+    <label for="sp-pagesize" i18n:translate="">Pagesize</label>
+  </td>
+</tr>
+
+   </table>
+
+</form>
+<pre tal:content="request" tal:condition=false />
+<script type="text/javascript"><!--
+  focus2id('username');
+//--></script>
+  </body>
+</html>
diff --git a/share/roundup/templates/classic/html/user.help.html b/share/roundup/templates/classic/html/user.help.html
new file mode 100644 (file)
index 0000000..b338c2b
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html tal:define="property request/form/property/value;
+qs request/env/QUERY_STRING;
+qs python:'&'.join([a for a in qs.split('&') if not a.startswith('@template=')]);
+form request/form/form/value;
+field request/form/property/value">
+  <head>
+      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+      <meta http-equiv="Content-Type"
+       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
+      <tal:block tal:condition="python:request.form.has_key('property')">
+      <title><tal:x i18n:translate=""><tal:x i18n:name="property"
+       tal:content="property" i18n:translate="" /> help - <span i18n:name="tracker"
+              tal:replace="config/TRACKER_NAME" /></tal:x></title>
+      <script language="Javascript" type="text/javascript"
+             tal:condition=false
+          tal:content="structure string:<!--
+          // this is the name of the field in the original form that we're working on
+          form  = window.opener.document.${form};
+          field  = '${field}';
+          //-->">
+      </script>
+      <script src="@@file/help_controls.js"
+     tal:condition=false type="text/javascript"><!--
+      //--></script>
+      </tal:block>
+  </head>
+<frameset rows="123,*,62">
+  <frame src="#" tal:attributes="src string:?@template=help-search&${qs}" name="search">
+  <!-- for search results: help-list -->
+  <frame
+  tal:attributes="src string:?@template=help-empty&${qs}"
+  name="list">
+  <frame
+  tal:attributes="src string:?@template=help-submit&${qs}"
+  name="submit">
+  <!-- -->
+</frameset>
+<noframes>
+  <body>
+<p i18n:translate="">
+Your browser is not capable of using frames; you should be redirected immediately,
+or visit <a href="#" tal:attributes="href string:?${qs}&template=help-noframes"
+i18n:name="link">this link</a>.
+</p>
+</body>
+</noframes>
+
+</html>
diff --git a/share/roundup/templates/classic/html/user.index.html b/share/roundup/templates/classic/html/user.index.html
new file mode 100644 (file)
index 0000000..021e2b8
--- /dev/null
@@ -0,0 +1,45 @@
+<!-- dollarId: user.index,v 1.3 2002/07/09 05:29:51 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">User listing - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">User listing</span>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))"
+ i18n:translate="">You are not allowed to view this page.</span>
+
+<span tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')"
+ i18n:translate="">Please login with your username and password.</span>
+
+<table width="100%" tal:condition="context/is_view_ok" class="list">
+<tr>
+ <th i18n:translate="">Username</th>
+ <th i18n:translate="">Real name</th>
+ <th i18n:translate="">Organisation</th>
+ <th i18n:translate="">Email address</th>
+ <th i18n:translate="">Phone number</th>
+ <th tal:condition="context/is_edit_ok" i18n:translate="">Retire</th>
+</tr>
+<tal:block repeat="user context/list">
+<tr tal:attributes="class python:['normal', 'alt'][repeat['user'].index%6/3]">
+ <td>
+  <a tal:attributes="href string:user${user/id}"
+     tal:content="user/username">username</a>
+ </td>
+ <td tal:content="python:user.realname.plain() or default">&nbsp;</td>
+ <td tal:content="python:user.organisation.plain() or default">&nbsp;</td>
+ <td tal:content="python:user.address.email() or default">&nbsp;</td>
+ <td tal:content="python:user.phone.plain() or default">&nbsp;</td>
+ <td tal:condition="context/is_edit_ok">
+  <a tal:attributes="href string:user${user/id}?@action=retire&@template=index"
+   i18n:translate="">retire</a>
+ </td>
+</tr>
+</tal:block>
+</table>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/user.item.html b/share/roundup/templates/classic/html/user.item.html
new file mode 100644 (file)
index 0000000..bafccd2
--- /dev/null
@@ -0,0 +1,169 @@
+<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
+<tal:doc metal:use-macro="templates/page/macros/icing"
+define="edit_ok context/is_edit_ok"
+>
+<title metal:fill-slot="head_title">
+<tal:if condition="context/id" i18n:translate=""
+ >User <tal:x content="context/id" i18n:name="id"
+ />: <tal:x content="context/username" i18n:name="title"
+ /> - <tal:x content="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:if>
+<tal:if condition="not:context/id" i18n:translate=""
+ >New User - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:if>
+</title>
+<metal:slot fill-slot="more-javascript">
+<script metal:use-macro="templates/page/macros/user_utils"></script>
+<script type="text/javascript" src="@@file/help_controls.js"></script>
+</metal:slot>
+<tal:block metal:fill-slot="body_title"
+  define="edit_ok context/is_edit_ok">
+ <span tal:condition="python: not (context.id or edit_ok)"
+  tal:omit-tag="python:1" i18n:translate="">New User</span>
+ <span tal:condition="python: not context.id and edit_ok"
+  tal:omit-tag="python:1" i18n:translate="">New User Editing</span>
+ <span tal:condition="python: context.id and not edit_ok"
+  tal:omit-tag="python:1" i18n:translate="">User<tal:x
+  replace="context/id" i18n:name="id" /></span>
+ <span tal:condition="python: context.id and edit_ok"
+  tal:omit-tag="python:1" i18n:translate="">User<tal:x
+  replace="context/id" i18n:name="id" /> Editing</span>
+</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<div tal:condition="context/is_view_ok">
+
+<form method="POST"
+      name="itemSynopsis"
+      tal:define="required python:'username address'.split()"
+      enctype="multipart/form-data"
+      tal:attributes="action context/designator;
+      onSubmit python:'return checkRequiredFields(\'%s\')'%'\', \''.join(required);
+      ">
+<table class="form" tal:define="
+  th_label templates/page/macros/th_label;
+  src_input templates/page/macros/user_src_input;
+  normal_input templates/page/macros/user_normal_input;
+  pw_input templates/page/macros/user_pw_input;
+  confirm_input templates/page/macros/user_confirm_input;
+  edit_ok context/is_edit_ok;
+  ">
+ <tr tal:define="name string:realname; label string:Name; value context/realname; edit_ok edit_ok">
+  <th metal:use-macro="th_label">Name</th>
+  <td><input name="realname" metal:use-macro="src_input"></td>
+ </tr>
+ <tr tal:define="name string:username; label string:Login Name; value context/username">
+   <th metal:use-macro="th_label">Login Name</th>
+   <td><input metal:use-macro="src_input"></td>
+ </tr>
+ <tal:if condition="edit_ok">
+ <tr tal:define="name string:password; label string:Login Password">
+  <th metal:use-macro="th_label">Login Password</th>
+  <td><input metal:use-macro="pw_input" type="password"></td>
+ </tr>
+ <tr tal:define="name string:password; label string:Confirm Password">
+  <th metal:use-macro="th_label">Confirm Password</th>
+  <td><input metal:use-macro="confirm_input" type="password"></td>
+ </tr>
+ </tal:if>
+ <tal:if condition="python:request.user.hasPermission('Web Roles')">
+ <tr tal:define="name string:roles; label string:Roles;">
+  <th><label for="roles" i18n:translate="">Roles</label></th>
+  <td tal:define="gips context/id">
+    <tal:subif condition=gips define="value context/roles">
+      <input metal:use-macro="normal_input">
+    </tal:subif>
+    <tal:subif condition="not:gips" define="value db/config/NEW_WEB_USER_ROLES">
+      <input metal:use-macro="normal_input">
+    </tal:subif>
+   <tal:block i18n:translate="">(to give the user more than one role,
+    enter a comma,separated,list)</tal:block>
+  </td>
+ </tr>
+ </tal:if>
+
+ <tr tal:define="name string:phone; label string:Phone; value context/phone">
+  <th metal:use-macro="th_label">Phone</th>
+  <td><input name="phone" metal:use-macro="normal_input"></td>
+ </tr>
+
+ <tr tal:define="name string:organisation; label string:Organisation; value context/organisation">
+  <th metal:use-macro="th_label">Organisation</th>
+  <td><input name="organisation" metal:use-macro="normal_input"></td>
+ </tr>
+
+ <tr tal:condition="python:edit_ok or context.timezone"
+     tal:define="name string:timezone; label string:Timezone; value context/timezone">
+  <th metal:use-macro="th_label">Timezone</th>
+  <td><input name="timezone" metal:use-macro="normal_input">
+   <tal:block tal:condition="edit_ok" i18n:translate="">(this is a numeric hour offset, the default is
+    <span tal:replace="db/config/DEFAULT_TIMEZONE" i18n:name="zone"
+    />)</tal:block>
+  </td>
+ </tr>
+
+ <tr tal:define="name string:address; label string:E-mail address; value context/address">
+  <th metal:use-macro="th_label">E-mail address</th>
+  <td tal:define="mailto python:context.address.field(id='address');
+         mklink python:mailto and not edit_ok">
+      <a href="mailto:calvin@the-z.org"
+                 tal:attributes="href string:mailto:$value"
+                 tal:content="value"
+          tal:condition="python:mklink">calvin@the-z.org</a>
+      <tal:if condition=edit_ok>
+      <input metal:use-macro="src_input" value="calvin@the-z.org">
+      </tal:if>
+      &nbsp;
+  </td>
+ </tr>
+
+ <tr>
+  <th><label for="alternate_addresses" i18n:translate="">Alternate E-mail addresses<br>One address per line</label></th>
+  <td>
+    <textarea rows=5 cols=40 tal:replace="structure context/alternate_addresses/multiline">nobody@nowhere.org
+anybody@everywhere.net
+(alternate_addresses)
+    </textarea>
+  </td>
+ </tr>
+
+ <tr tal:condition="edit_ok">
+  <td>
+   &nbsp;
+   <input type="hidden" name="@template" value="item">
+   <input type="hidden" name="@required" value="username,address"
+          tal:attributes="value python:','.join(required)">
+  </td>
+  <td><input type="submit" value="save" tal:replace="structure context/submit"><!--submit button here-->
+    <input type=reset>
+  </td>
+ </tr>
+</table>
+</form>
+
+<tal:block tal:condition="not:context/id" i18n:translate="">
+<table class="form">
+<tr>
+ <td>Note:&nbsp;</td>
+ <th class="required">highlighted</th>
+ <td>&nbsp;fields are required.</td>
+</tr>
+</table>
+</tal:block>
+
+<tal:block tal:condition="context/id" tal:replace="structure context/history" />
+
+</div>
+
+</td>
+
+</tal:doc>
diff --git a/share/roundup/templates/classic/html/user.register.html b/share/roundup/templates/classic/html/user.register.html
new file mode 100644 (file)
index 0000000..b7b1749
--- /dev/null
@@ -0,0 +1,81 @@
+<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title"
+ i18n:translate="">Registering with <span i18n:name="tracker"
+ tal:replace="db/config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Registering with <span i18n:name="tracker"
+ tal:replace="db/config/TRACKER_NAME" /></span>
+<td class="content" metal:fill-slot="content">
+
+<form method="POST" onSubmit="return submit_once()"
+      enctype="multipart/form-data"
+      tal:attributes="action context/designator">
+
+<table class="form">
+ <tr>
+  <th i18n:translate="">Name</th>
+  <td tal:content="structure context/realname/field">realname</td>
+ </tr>
+ <tr>
+  <th class="required" i18n:translate="">Login Name</th>
+  <td tal:content="structure context/username/field">username</td>
+ </tr>
+ <tr>
+  <th class="required" i18n:translate="">Login Password</th>
+  <td tal:content="structure context/password/field">password</td>
+ </tr>
+ <tr>
+  <th class="required" i18n:translate="">Confirm Password</th>
+  <td tal:content="structure context/password/confirm">password</td>
+ </tr>
+ <tr tal:condition="python:request.user.hasPermission('Web Roles')">
+  <th i18n:translate="">Roles</th>
+  <td tal:condition="exists:item"
+      tal:content="structure context/roles/field">roles</td>
+  <td tal:condition="not:exists:item">
+   <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Phone</th>
+  <td tal:content="structure context/phone/field">phone</td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Organisation</th>
+  <td tal:content="structure context/organisation/field">organisation</td>
+ </tr>
+ <tr>
+  <th class="required" i18n:translate="">E-mail address</th>
+  <td tal:content="structure context/address/field">address</td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Alternate E-mail addresses<br>One address per line</th>
+  <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
+ </tr>
+
+ <tr>
+  <td>&nbsp;</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="submit" name="submit" value="Register" i18n:attributes="value">
+  </td>
+ </tr>
+</table>
+</form>
+
+<tal:block tal:condition="not:context/id" i18n:translate="">
+<table class="form">
+<tr>
+ <td>Note:&nbsp;</td>
+ <th class="required">highlighted</th>
+ <td>&nbsp;fields are required.</td>
+</tr>
+</table>
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/classic/html/user.rego_progress.html b/share/roundup/templates/classic/html/user.rego_progress.html
new file mode 100644 (file)
index 0000000..4d6bfe4
--- /dev/null
@@ -0,0 +1,16 @@
+<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title"
+ i18n:translate="">Registration in progress - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Registration in progress...</span>
+<td class="content" metal:fill-slot="content">
+
+<p i18n:translate="">You will shortly receive an email
+to confirm your registration. To complete the registration process,
+visit the link indicated in the email.
+</p>
+
+</td>
+</tal:block>
diff --git a/share/roundup/templates/classic/html/user_utils.js b/share/roundup/templates/classic/html/user_utils.js
new file mode 100644 (file)
index 0000000..7b2946d
--- /dev/null
@@ -0,0 +1,114 @@
+// User Editing Utilities
+
+/**
+ * for new users:
+ * Depending on the input field which calls it, takes the value
+ * and dispatches it to certain other input fields:
+ *
+ * address
+ *  +-> username
+ *  |    `-> realname
+ *  `-> organisation
+ */
+function split_name(that) {
+    var raw = that.value
+    var val = trim(raw)
+    if (val == '') {
+        return
+    }
+    var username=''
+    var realname=''
+    var address=''
+    switch (that.name) {
+        case 'address':
+            address=val
+            break
+        case 'username':
+            username=val
+            break
+        case 'realname':
+            realname=val
+            break
+        case 'firstname':
+        case 'lastname':
+           return
+        default:
+            alert('Ooops - unknown name field '+that.name+'!')
+            return
+    }
+    var the_form = that.form;
+
+    function field_empty(name) {
+        return the_form[name].value == ''
+    }
+
+    // no break statements - on purpose!
+    switch (that.name) {
+        case 'address':
+            var split1 = address.split('@')
+            if (field_empty('username')) {
+                username = split1[0]
+                the_form.username.value = username
+            }
+            if (field_empty('organisation')) {
+                the_form.organisation.value = default_organisation(split1[1])
+            }
+        case 'username':
+            if (field_empty('realname')) {
+                realname = Cap(username.split('.').join(' '))
+                the_form.realname.value = realname
+            }
+        case 'realname':
+            if (field_empty('username')) {
+                username = Cap(realname.replace(' ', '.'))
+                the_form.username.value = username
+            }
+            if (the_form.firstname && the_form.lastname) {
+                var split2 = realname.split(' ')
+                var firstname='', lastname=''
+                firstname = split2[0]
+                lastname = split2.slice(1).join(' ')
+                if (field_empty('firstname')) {
+                    the_form.firstname.value = firstname
+                }
+                if (field_empty('lastname')) {
+                    the_form.lastname.value = lastname
+                }
+            }
+    }
+}
+
+function SubCap(str) {
+    switch (str) {
+        case 'de': case 'do': case 'da':
+        case 'du': case 'von':
+            return str;
+    }
+    if (str.toLowerCase().slice(0,2) == 'mc') {
+        return 'Mc'+str.slice(2,3).toUpperCase()+str.slice(3).toLowerCase()
+    }
+    return str.slice(0,1).toUpperCase()+str.slice(1).toLowerCase()
+}
+
+function Cap(str) {
+    var liz = str.split(' ')
+    for (var i=0; i<liz.length; i++) {
+        liz[i] = SubCap(liz[i])
+    }
+    return liz.join(' ')
+}
+
+/**
+ * Takes a domain name (behind the @ part of an email address)
+ * Customise this to handle the mail domains you're interested in 
+ */
+function default_organisation(orga) {
+    switch (orga.toLowerCase()) {
+        case 'gmx':
+        case 'yahoo':
+            return ''
+        default:
+            return orga
+    }
+}
+
diff --git a/share/roundup/templates/classic/initial_data.py b/share/roundup/templates/classic/initial_data.py
new file mode 100644 (file)
index 0000000..101768b
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# TRACKER INITIAL PRIORITY AND STATUS VALUES
+#
+pri = db.getclass('priority')
+pri.create(name=''"critical", order="1")
+pri.create(name=''"urgent", order="2")
+pri.create(name=''"bug", order="3")
+pri.create(name=''"feature", order="4")
+pri.create(name=''"wish", order="5")
+
+stat = db.getclass('status')
+stat.create(name=''"unread", order="1")
+stat.create(name=''"deferred", order="2")
+stat.create(name=''"chatting", order="3")
+stat.create(name=''"need-eg", order="4")
+stat.create(name=''"in-progress", order="5")
+stat.create(name=''"testing", order="6")
+stat.create(name=''"done-cbb", order="7")
+stat.create(name=''"resolved", order="8")
+
+# create the two default users
+user = db.getclass('user')
+user.create(username="admin", password=adminpw,
+    address=admin_email, roles='Admin')
+user.create(username="anonymous", roles='Anonymous')
+
+# add any additional database creation steps here - but only if you
+# haven't initialised the database with the admin "initialise" command
+
+
+# vim: set filetype=python sts=4 sw=4 et si
+#SHA: b1da2e72a7fe9f26086f243eb744135b085101d9
diff --git a/share/roundup/templates/classic/schema.py b/share/roundup/templates/classic/schema.py
new file mode 100644 (file)
index 0000000..85fa495
--- /dev/null
@@ -0,0 +1,169 @@
+
+#
+# TRACKER SCHEMA
+#
+
+# Class automatically gets these properties:
+#   creation = Date()
+#   activity = Date()
+#   creator = Link('user')
+#   actor = Link('user')
+
+# Priorities
+pri = Class(db, "priority",
+                name=String(),
+                order=Number())
+pri.setkey("name")
+
+# Statuses
+stat = Class(db, "status",
+                name=String(),
+                order=Number())
+stat.setkey("name")
+
+# Keywords
+keyword = Class(db, "keyword",
+                name=String())
+keyword.setkey("name")
+
+# User-defined saved searches
+query = Class(db, "query",
+                klass=String(),
+                name=String(),
+                url=String(),
+                private_for=Link('user'))
+
+# add any additional database schema configuration here
+
+user = Class(db, "user",
+                username=String(),
+                password=Password(),
+                address=String(),
+                realname=String(),
+                phone=String(),
+                organisation=String(),
+                alternate_addresses=String(),
+                queries=Multilink('query'),
+                roles=String(),     # comma-separated string of Role names
+                timezone=String())
+user.setkey("username")
+
+# FileClass automatically gets this property in addition to the Class ones:
+#   content = String()    [saved to disk in <tracker home>/db/files/]
+#   type = String()       [MIME type of the content, default 'text/plain']
+msg = FileClass(db, "msg",
+                author=Link("user", do_journal='no'),
+                recipients=Multilink("user", do_journal='no'),
+                date=Date(),
+                summary=String(),
+                files=Multilink("file"),
+                messageid=String(),
+                inreplyto=String())
+
+file = FileClass(db, "file",
+                name=String())
+
+# IssueClass automatically gets these properties in addition to the Class ones:
+#   title = String()
+#   messages = Multilink("msg")
+#   files = Multilink("file")
+#   nosy = Multilink("user")
+#   superseder = Multilink("issue")
+issue = IssueClass(db, "issue",
+                assignedto=Link("user"),
+                keyword=Multilink("keyword"),
+                priority=Link("priority"),
+                status=Link("status"))
+
+#
+# TRACKER SECURITY SETTINGS
+#
+# See the configuration and customisation document for information
+# about security setup.
+
+#
+# REGULAR USERS
+#
+# Give the regular users access to the web and email interface
+db.security.addPermissionToRole('User', 'Web Access')
+db.security.addPermissionToRole('User', 'Email Access')
+
+# Assign the access and edit Permissions for issue, file and message
+# to regular users now
+for cl in 'issue', 'file', 'msg', 'keyword':
+    db.security.addPermissionToRole('User', 'View', cl)
+    db.security.addPermissionToRole('User', 'Edit', cl)
+    db.security.addPermissionToRole('User', 'Create', cl)
+for cl in 'priority', 'status':
+    db.security.addPermissionToRole('User', 'View', cl)
+
+# May users view other user information? Comment these lines out
+# if you don't want them to
+db.security.addPermissionToRole('User', 'View', 'user')
+
+# Users should be able to edit their own details -- this permission is
+# limited to only the situation where the Viewed or Edited item is their own.
+def own_record(db, userid, itemid):
+    '''Determine whether the userid matches the item being accessed.'''
+    return userid == itemid
+p = db.security.addPermission(name='View', klass='user', check=own_record,
+    description="User is allowed to view their own user details")
+db.security.addPermissionToRole('User', p)
+p = db.security.addPermission(name='Edit', klass='user', check=own_record,
+    description="User is allowed to edit their own user details")
+db.security.addPermissionToRole('User', p)
+
+# Users should be able to edit and view their own queries. They should also
+# be able to view any marked as not private. They should not be able to
+# edit others' queries, even if they're not private
+def view_query(db, userid, itemid):
+    private_for = db.query.get(itemid, 'private_for')
+    if not private_for: return True
+    return userid == private_for
+def edit_query(db, userid, itemid):
+    return userid == db.query.get(itemid, 'creator')
+p = db.security.addPermission(name='View', klass='query', check=view_query,
+    description="User is allowed to view their own and public queries")
+db.security.addPermissionToRole('User', p)
+p = db.security.addPermission(name='Edit', klass='query', check=edit_query,
+    description="User is allowed to edit their queries")
+db.security.addPermissionToRole('User', p)
+p = db.security.addPermission(name='Create', klass='query',
+    description="User is allowed to create queries")
+db.security.addPermissionToRole('User', p)
+
+
+#
+# ANONYMOUS USER PERMISSIONS
+#
+# Let anonymous users access the web interface. Note that almost all
+# trackers will need this Permission. The only situation where it's not
+# required is in a tracker that uses an HTTP Basic Authenticated front-end.
+db.security.addPermissionToRole('Anonymous', 'Web Access')
+
+# Let anonymous users access the email interface (note that this implies
+# that they will be registered automatically, hence they will need the
+# "Create" user Permission below)
+# This is disabled by default to stop spam from auto-registering users on
+# public trackers.
+#db.security.addPermissionToRole('Anonymous', 'Email Access')
+
+# Assign the appropriate permissions to the anonymous user's Anonymous
+# Role. Choices here are:
+# - Allow anonymous users to register
+db.security.addPermissionToRole('Anonymous', 'Create', 'user')
+
+# Allow anonymous users access to view issues (and the related, linked
+# information)
+for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status':
+    db.security.addPermissionToRole('Anonymous', 'View', cl)
+
+# [OPTIONAL]
+# Allow anonymous users access to create or edit "issue" items (and the
+# related file and message items)
+#for cl in 'issue', 'file', 'msg':
+#   db.security.addPermissionToRole('Anonymous', 'Create', cl)
+#   db.security.addPermissionToRole('Anonymous', 'Edit', cl)
+
+
+# vim: set filetype=python sts=4 sw=4 et si :
diff --git a/share/roundup/templates/minimal/.cvsignore b/share/roundup/templates/minimal/.cvsignore
new file mode 100644 (file)
index 0000000..d90d51d
--- /dev/null
@@ -0,0 +1,4 @@
+*.pyc
+*.pyo
+htmlbase.py
+*.cover
diff --git a/share/roundup/templates/minimal/TEMPLATE-INFO.txt b/share/roundup/templates/minimal/TEMPLATE-INFO.txt
new file mode 100644 (file)
index 0000000..0cb35b5
--- /dev/null
@@ -0,0 +1,8 @@
+Name: minimal
+Description: This is an empty tracker - it must be customised for it to be
+             useful! It only defines the bare minimum of information - the
+             user database and the two default users (admin and anonymous).
+             The rest is entirely up to you! Not recommended for first-time
+             Roundup users (it's easier to tweak the Classic tracker).
+Intended-For: Roundup experts who need a clean slate to start with.
+
diff --git a/share/roundup/templates/minimal/detectors/.cvsignore b/share/roundup/templates/minimal/detectors/.cvsignore
new file mode 100644 (file)
index 0000000..4162d5e
--- /dev/null
@@ -0,0 +1,3 @@
+*.pyc
+*.pyo
+*.cover
diff --git a/share/roundup/templates/minimal/detectors/userauditor.py b/share/roundup/templates/minimal/detectors/userauditor.py
new file mode 100644 (file)
index 0000000..dd7fcc4
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net)
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+#   The above copyright notice and this permission notice shall be included in
+#   all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#$Id: userauditor.py,v 1.8 2007-09-12 21:11:14 jpend Exp $
+
+import re
+
+# regular expression thanks to: http://www.regular-expressions.info/email.html
+# this is the "99.99% solution for syntax only".
+email_regexp = (r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*", r"(localhost|(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]))")
+email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
+email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
+
+def valid_address(address):
+    ''' If we see an @-symbol in the address then check against the full
+        RFC syntax. Otherwise it is a local-only address so only check
+        the local part of the RFC syntax.
+    '''
+    if '@' in address:
+        return email_rfc.match(address)
+    else:
+        return email_local.match(address)
+
+def get_addresses(user):
+    ''' iterate over all known addresses in a newvalues dict
+        this takes of the address/alterate_addresses handling
+    '''
+    if user.has_key('address'):
+        yield user['address']
+    if user.get('alternate_addresses', None):
+        for address in user['alternate_addresses'].split('\n'):
+            yield address
+
+def audit_user_fields(db, cl, nodeid, newvalues):
+    ''' Make sure user properties are valid.
+
+        - email address is syntactically valid
+        - email address is unique
+        - roles specified exist
+        - timezone is valid
+    '''
+
+    for address in get_addresses(newvalues):
+        if not valid_address(address):
+            raise ValueError, 'Email address syntax is invalid'
+
+        check_main = db.user.stringFind(address=address)
+        # make sure none of the alts are owned by anyone other than us (x!=nodeid)
+        check_alts = [x for x in db.user.filter(None, {'alternate_addresses' : address}) if x != nodeid]
+        if check_main or check_alts:
+            raise ValueError, 'Email address %s already in use' % address
+
+    for rolename in [r.lower().strip() for r in newvalues.get('roles', '').split(',')]:
+            if rolename and not db.security.role.has_key(rolename):
+                raise ValueError, 'Role "%s" does not exist'%rolename
+
+    tz = newvalues.get('timezone', None)
+    if tz:
+        # if they set a new timezone validate the timezone by attempting to
+        # use it before we store it to the db.
+        import roundup.date
+        import datetime
+        try:
+            TZ = roundup.date.get_timezone(tz)
+            dt = datetime.datetime.now()
+            local = TZ.localize(dt).utctimetuple()
+        except IOError:
+            raise ValueError, 'Timezone "%s" does not exist' % tz
+        except ValueError:
+            raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz
+
+def init(db):
+    # fire before changes are made
+    db.user.audit('set', audit_user_fields)
+    db.user.audit('create', audit_user_fields)
+
+# vim: sts=4 sw=4 et si
diff --git a/share/roundup/templates/minimal/extensions/README.txt b/share/roundup/templates/minimal/extensions/README.txt
new file mode 100644 (file)
index 0000000..ff4dff3
--- /dev/null
@@ -0,0 +1,6 @@
+This directory is for tracker extensions:
+
+- CGI Actions
+- Templating functions
+
+See the customisation doc for more information.
diff --git a/share/roundup/templates/minimal/html/_generic.404.html b/share/roundup/templates/minimal/html/_generic.404.html
new file mode 100644 (file)
index 0000000..71c9e0e
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Item Not Found</title>
+</head>
+
+<body>
+There is no <span tal:content="context/_classname" /> with id <span tal:content="context/id"/>
+</body>
+</html>
diff --git a/share/roundup/templates/minimal/html/_generic.calendar.html b/share/roundup/templates/minimal/html/_generic.calendar.html
new file mode 100644 (file)
index 0000000..dbc3b57
--- /dev/null
@@ -0,0 +1,18 @@
+<!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" />
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" />
+  <title tal:content="string:Roundup Calendar"></title>
+  <script language="Javascript"
+          type="text/javascript"
+          tal:content="structure string:
+          // this is the name of the field in the original form that we're working on
+          form  = window.opener.document.${request/form/form/value};
+          field = '${request/form/property/value}';" >
+  </script>
+ </head>
+ <body class="body"
+       tal:content="structure python:utils.html_calendar (request)">
+ </body>
+</html>
diff --git a/share/roundup/templates/minimal/html/_generic.collision.html b/share/roundup/templates/minimal/html/_generic.collision.html
new file mode 100644 (file)
index 0000000..2a2768a
--- /dev/null
@@ -0,0 +1,16 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> Edit Collision - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<tal:block metal:fill-slot="body_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> Edit Collision</tal:block>
+
+<td class="content" metal:fill-slot="content" i18n:translate="
+  There has been a collision. Another user updated this node
+  while you were editing. Please <a href='${context}'>reload</a>
+  the node and review your edits.
+"><span tal:replace="context/designator" i18n:name="context" />
+</td>
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/_generic.help.html b/share/roundup/templates/minimal/html/_generic.help.html
new file mode 100644 (file)
index 0000000..069c0a6
--- /dev/null
@@ -0,0 +1,98 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html tal:define="property request/form/property/value" >
+  <head>
+      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
+      <meta http-equiv="Content-Type"
+       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
+      <tal:block tal:condition="python:request.form.has_key('property')">
+      <title i18n:translate=""><tal:x i18n:name="property"
+       tal:content="property" i18n:translate="" /> help - <span i18n:name="tracker"
+       tal:replace="config/TRACKER_NAME" /></title>
+      <script language="Javascript" type="text/javascript"
+          tal:content="structure string:
+          // this is the name of the field in the original form that we're working on
+          form  = window.opener.document.${request/form/form/value};
+          field  = '${request/form/property/value}';">
+      </script>
+      <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="batch request/batch;
+                   props python:request.form['properties'].value.split(',')">
+
+     <div id="classhelp-controls">
+       <!--input type="button" name="btn_clear"
+              value="Clear" onClick="clearList()"/ -->
+       <input type="text" name="text_preview" size="24" class="preview"
+              onchange="reviseList(this.value);"/>
+       <input type="button" name="btn_reset"
+              value=" Cancel " onclick="resetList(); window.close();"
+              i18n:attributes="value" />
+       <input type="button" name="btn_apply" class="apply"
+              value=" Apply " onclick="updateList(); window.close();"
+              i18n:attributes="value" />
+     </div>
+     <table width="100%">
+      <tr class="navigation">
+       <th>
+        <a tal:define="prev batch/previous" tal:condition="prev"
+           tal:attributes="href python:request.indexargs_url(request.classname,
+           {'@template':'help', 'property': request.form['property'].value,
+            'properties': request.form['properties'].value,
+            'form': request.form['form'].value,
+            'type': request.form['type'].value,
+            '@startwith':prev.first, '@pagesize':prev.size})"
+           i18n:translate="" >&lt;&lt; previous</a>
+        &nbsp;
+       </th>
+       <th i18n:translate=""><span tal:replace="batch/start" i18n:name="start"
+        />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
+        /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
+        />
+       </th>
+       <th>
+        <a tal:define="next batch/next" tal:condition="next"
+           tal:attributes="href python:request.indexargs_url(request.classname,
+           {'@template':'help', 'property': request.form['property'].value,
+            'properties': request.form['properties'].value,
+            'form': request.form['form'].value,
+            'type': request.form['type'].value,
+            '@startwith':next.first, '@pagesize':next.size})"
+           i18n:translate="" >next &gt;&gt;</a>
+        &nbsp;
+       </th>
+      </tr>
+     </table>
+
+     <table class="classhelp">
+       <tr>
+           <th>&nbsp;<b>x</b></th>
+           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
+       </tr>
+       <tr tal:repeat="item batch">
+         <tal:block tal:define="attr python:item[props[0]]" >
+           <td>
+             <input name="check"
+                 onclick="updatePreview();"
+                 tal:attributes="type python:request.form['type'].value;
+                                 value attr; id string:id_$attr" />
+             </td>
+             <td tal:repeat="prop props">
+                 <label class="classhelp-label"
+                        tal:attributes="for string:id_$attr"
+                        tal:content="python:item[prop]"></label>
+             </td>
+           </tal:block>
+       </tr>
+       <tr>
+           <th>&nbsp;<b>x</b></th>
+           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
+       </tr>
+     </table>
+
+ </form>
+ </body>
+</html>
diff --git a/share/roundup/templates/minimal/html/_generic.index.html b/share/roundup/templates/minimal/html/_generic.index.html
new file mode 100644 (file)
index 0000000..81918ef
--- /dev/null
@@ -0,0 +1,70 @@
+<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<tal:block metal:fill-slot="body_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok()
+ or request.user.hasRole('Anonymous'))"
+ tal:omit-tag="python:1" i18n:translate=""
+>You are not allowed to view this page.</span>
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())
+ and request.user.hasRole('Anonymous')"
+ tal:omit-tag="python:1" i18n:translate=""
+>Please login with your username and password.</span>
+
+<tal:block tal:condition="context/is_edit_ok">
+<tal:block i18n:translate="">
+<p class="form-help">
+ You may edit the contents of the
+ <span tal:replace="request/classname" i18n:name="classname"/>
+ class using this form. Commas, newlines and double quotes (") must be
+ handled delicately. You may include commas and newlines by enclosing the
+ values in double-quotes ("). Double quotes themselves must be quoted by
+ doubling ("").
+</p>
+
+<p class="form-help">
+ Multilink properties have their multiple values colon (":") separated
+ (... ,"one:two:three", ...)
+</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>
+</tal:block>
+<form onSubmit="return submit_once()" method="POST"
+      tal:attributes="action context/designator">
+<textarea rows="15" style="width:90%" name="rows" tal:content="context/csv"></textarea>
+<br>
+<input type="hidden" name="@action" value="editCSV">
+<input type="submit" value="Edit Items" i18n:attributes="value">
+</form>
+</tal:block>
+
+<table tal:condition="context/is_only_view_ok" width="100%" class="list">
+ <tr>
+  <th tal:repeat="property context/propnames" tal:content="property">&nbsp;</th>
+ </tr>
+ <tal:block repeat="item context/list">
+ <tr tal:condition="item/is_view_ok"
+     tal:attributes="class python:['normal', 'alt'][repeat['item'].index%6/3]">
+  <td tal:repeat="property context/propnames"
+   tal:content="python: item[property] or default"
+  >&nbsp;</td>
+  </tr>
+ </tal:block>
+</table>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/_generic.item.html b/share/roundup/templates/minimal/html/_generic.item.html
new file mode 100644 (file)
index 0000000..ac60acb
--- /dev/null
@@ -0,0 +1,65 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<tal:block metal:fill-slot="body_title" i18n:translate=""
+ ><span tal:replace="python:context._classname.capitalize()"
+ i18n:name="class" /> editing</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok()
+ or request.user.hasRole('Anonymous'))"
+ tal:omit-tag="python:1" i18n:translate=""
+>You are not allowed to view this page.</span>
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())
+ and request.user.hasRole('Anonymous')"
+ tal:omit-tag="python:1" i18n:translate=""
+>Please login with your username and password.</span>
+
+<form method="POST" onSubmit="return submit_once()"
+      enctype="multipart/form-data" tal:condition="context/is_edit_ok"
+      tal:attributes="action context/designator">
+
+<input type="hidden" name="@template" value="item">
+
+<table class="form">
+
+<tr tal:repeat="prop python:db[context._classname].properties()">
+ <tal:block tal:condition="python:prop._name not in ('id',
+   'creator', 'creation', 'actor', 'activity')">
+  <th tal:content="prop/_name"></th>
+  <td tal:content="structure python:context[prop._name].field()"></td>
+ </tal:block>
+</tr>
+<tr>
+ <td>&nbsp;</td>
+ <td colspan=3 tal:content="structure context/submit">
+  submit button will go here
+ </td>
+</tr>
+</table>
+
+</form>
+
+<table class="form" tal:condition="context/is_only_view_ok">
+
+<tr tal:repeat="prop python:db[context._classname].properties()">
+ <tal:block tal:condition="python:prop._name not in ('id', 'creator',
+                                  'creation', 'activity')">
+  <th tal:content="prop/_name"></th>
+  <td tal:content="structure python:context[prop._name].field()"></td>
+ </tal:block>
+</tr>
+</table>
+
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()">
+ <tal:block tal:replace="structure context/history" />
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/help_controls.js b/share/roundup/templates/minimal/html/help_controls.js
new file mode 100644 (file)
index 0000000..d3b5529
--- /dev/null
@@ -0,0 +1,111 @@
+// initial values for either Nosy, Superseder, Keyword and Waiting On,
+// depending on which has called
+original_field = form[field].value;
+
+// Some browsers (ok, IE) don't define the "undefined" variable.
+undefined = document.geez_IE_is_really_friggin_annoying;
+
+function trim(value) {
+  var temp = value;
+  var obj = /^(\s*)([\W\w]*)(\b\s*$)/;
+  if (obj.test(temp)) { temp = temp.replace(obj, '$2'); }
+  var obj = /  /g;
+  while (temp.match(obj)) { temp = temp.replace(obj, " "); }
+  return temp;
+}
+
+function determineList() {
+    // generate a comma-separated list of the checked items
+    var list = new String('');
+    for (box=0; box < document.frm_help.check.length; box++) {
+        if (document.frm_help.check[box].checked) {
+            if (list.length == 0) {
+                separator = '';
+            }
+            else {
+                separator = ',';
+            }
+            // we used to use an Array and push / join, but IE5.0 sux
+            list = list + separator + document.frm_help.check[box].value;
+        }
+    }
+    return list;
+}
+
+function updateList() {
+  // write back to opener window
+  if (document.frm_help.check==undefined) { return; }
+  form[field].value = determineList();
+}
+
+function updatePreview() {
+  // update the preview box
+  if (document.frm_help.check==undefined) { return; }
+  writePreview(determineList());
+}
+
+function clearList() {
+  // uncheck all checkboxes
+  if (document.frm_help.check==undefined) { return; }
+  for (box=0; box < document.frm_help.check.length; box++) {
+      document.frm_help.check[box].checked = false;
+  }
+}
+
+function reviseList(vals) {
+  // update the checkboxes based on the preview field
+  if (document.frm_help.check==undefined) { return; }
+  var to_check;
+  var list = vals.split(",");
+  if (document.frm_help.check.length==undefined) {
+      check = document.frm_help.check;
+      to_check = false;
+      for (val in list) {
+          if (check.value==trim(list[val])) {
+              to_check = true;
+              break;
+          }
+      }
+      check.checked = to_check;
+  } else {
+    for (box=0; box < document.frm_help.check.length; box++) {
+      check = document.frm_help.check[box];
+      to_check = false;
+      for (val in list) {
+          if (check.value==trim(list[val])) {
+              to_check = true;
+              break;
+          }
+      }
+      check.checked = to_check;
+    }
+  }
+}
+
+function resetList() {
+  // reset preview and check boxes to initial values
+  if (document.frm_help.check==undefined) { return; }
+  writePreview(original_field);
+  reviseList(original_field);
+}
+
+function writePreview(val) {
+   // writes a value to the text_preview
+   document.frm_help.text_preview.value = val;
+}
+
+function focusField(name) {
+    for(i=0; i < document.forms.length; ++i) {
+      var obj = document.forms[i].elements[name];
+      if (obj && obj.focus) {obj.focus();}
+    }
+}
+
+function selectField(name) {
+    for(i=0; i < document.forms.length; ++i) {
+      var obj = document.forms[i].elements[name];
+      if (obj && obj.focus){obj.focus();} 
+      if (obj && obj.select){obj.select();}
+    }
+}
+
diff --git a/share/roundup/templates/minimal/html/home.classlist.html b/share/roundup/templates/minimal/html/home.classlist.html
new file mode 100644 (file)
index 0000000..930306b
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">List of classes - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">List of classes</span>
+<td class="content" metal:fill-slot="content">
+<table class="classlist">
+
+<tal:block tal:repeat="cl db/classes">
+ <tr>
+  <th class="header" colspan="2" align="left">
+   <a tal:attributes="href string:${cl/classname}"
+      tal:content="python:cl.classname.capitalize()">classname</a>
+  </th>
+ </tr>
+ <tr tal:repeat="prop cl/properties">
+  <th tal:content="prop/_name">name</th>
+  <td tal:content="prop/_prop">type</td>
+ </tr>
+</tal:block>
+
+</table>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/home.html b/share/roundup/templates/minimal/html/home.html
new file mode 100644 (file)
index 0000000..c933c59
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">Tracker home - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Tracker home</span>
+<td class="content" metal:fill-slot="content">
+
+<!--
+ This is the default body that is displayed when people visit the
+ tracker. The tag below lists the currently open issues. You may
+ replace it with a greeting message, or a different list of issues or
+ whatever. It's a good idea to have the issues on the front page though
+-->
+
+<tal:block tal:define="anon python:request.user.username == 'anonymous'">
+<p tal:condition="not:anon" class="help" i18n:translate="">
+Please select from one of the menu options on the left.
+</p>
+<p tal:condition="anon" class="help" i18n:translate="">
+Please log in or register.
+</p>
+</tal:block>
+
+</td>
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/page.html b/share/roundup/templates/minimal/html/page.html
new file mode 100644 (file)
index 0000000..dbbbb5e
--- /dev/null
@@ -0,0 +1,334 @@
+<!-- vim:sw=2 sts=2
+--><tal:block metal:define-macro="icing"
+><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title metal:define-slot="head_title">title goes here</title>
+<link rel="stylesheet" type="text/css" href="@@file/style.css">
+<meta http-equiv="Content-Type"
+ tal:attributes="content string:text/html;; charset=${request/client/charset}" />
+<script tal:replace="structure request/base_javascript">
+</script>
+<metal:x define-slot="more-javascript" />
+
+</head>
+<body class="body">
+
+<table class="body"
+ tal:define="
+kw_edit python:request.user.hasPermission('Edit', 'keyword');
+kw_create python:request.user.hasPermission('Create', 'keyword');
+kw_edit_link python:kw_edit and db.keyword.list();
+columns string:id,activity,title,creator,status;
+columns_showall string:id,activity,title,creator,assignedto,status;
+status_notresolved string:-1,1,2,3,4,5,6,7;
+"
+>
+
+<tr>
+ <td class="page-header-left">&nbsp;</td>
+ <td class="page-header-top">
+   <div id="body-title">
+     <h2><span metal:define-slot="body_title">body title</span></h2>
+   </div>
+   <div id="searchbox">
+     <form method="GET" action="issue">
+       <input type="hidden" name="@columns"
+             tal:attributes="value columns_showall"
+             value="id,activity,title,creator,assignedto,status"/>
+       <input type="hidden" name="@sort" value="activity"/>
+       <input type="hidden" name="@group" value="priority"/>
+       <input id="search-text" name="@search_text" size="10"
+              tal:attributes="value request/search_text"/>
+       <input type="submit" id="submit" name="submit" value="Search" i18n:attributes="value" />
+     </form>
+  </div>
+ </td>
+</tr>
+
+<tr>
+ <td rowspan="2" valign="top" class="sidebar">
+  <p class="classblock"
+     tal:condition="python:request.user.hasPermission('View', 'query')">
+   <span i18n:translate=""
+    ><b>Your Queries</b> (<a href="query?@template=edit">edit</a>)</span><br>
+   <tal:block tal:repeat="qs request/user/queries">
+    <a href="#" tal:attributes="href string:${qs/klass}?${qs/url}&@dispname=${qs/name}"
+       tal:content="qs/name">link</a><br>
+   </tal:block>
+  </p>
+
+  <form method="POST" tal:attributes="action request/base">
+   <p class="classblock"
+       tal:condition="python:request.user.hasPermission('View', 'issue')">
+    <b i18n:translate="">Issues</b><br>
+    <span tal:condition="python:request.user.hasPermission('Create', 'issue')">
+      <a href="issue?@template=item" i18n:translate="">Create New</a><br>
+    </span>
+    <a href="#"
+       tal:attributes="href python:request.indexargs_url('issue', {
+      '@sort': '-activity',
+      '@group': 'priority',
+      '@filter': 'status,assignedto',
+      '@columns': columns,
+      '@search_text': '',
+      'status': status_notresolved,
+      'assignedto': '-1',
+      '@dispname': i18n.gettext('Show Unassigned'),
+     })"
+       i18n:translate="">Show Unassigned</a><br>
+    <a href="#"
+       tal:attributes="href python:request.indexargs_url('issue', {
+      '@sort': '-activity',
+      '@group': 'priority',
+      '@filter': 'status',
+      '@columns': columns_showall,
+      '@search_text': '',
+      'status': status_notresolved,
+      '@dispname': i18n.gettext('Show All'),
+     })"
+       i18n:translate="">Show All</a><br>
+    <a href="issue?@template=search" i18n:translate="">Search</a><br>
+    <input type="submit" class="form-small" value="Show issue:"
+     i18n:attributes="value"><input class="form-small" size="4"
+     type="text" name="@number">
+    <input type="hidden" name="@type" value="issue">
+    <input type="hidden" name="@action" value="show">
+   </p>
+  </form>
+
+  <p class="classblock"
+     tal:condition="python:kw_edit or kw_create">
+   <b i18n:translate="">Keywords</b><br>
+   <span tal:condition="python:request.user.hasPermission('Create', 'keyword')">
+    <a href="keyword?@template=item" i18n:translate="">Create New</a><br>
+   </span>
+   <span tal:condition="kw_edit_link">
+    <a href="keyword?@template=item" i18n:translate="">Edit Existing</a><br>
+   </span>
+  </p>
+
+  <p class="classblock"
+       tal:condition="python:request.user.hasPermission('View', 'user')">
+   <b i18n:translate="">Administration</b><br>
+   <span tal:condition="python:request.user.hasPermission('Edit', None)">
+    <a href="home?@template=classlist" i18n:translate="">Class List</a><br>
+   </span>
+   <span tal:condition="python:request.user.hasPermission('View', 'user')
+                            or request.user.hasPermission('Edit', 'user')">
+    <a href="user"  i18n:translate="">User List</a><br>
+   </span>
+   <a tal:condition="python:request.user.hasPermission('Create', 'user')"
+      href="user?@template=item" i18n:translate="">Add User</a>
+  </p>
+
+  <form method="POST" tal:condition="python:request.user.username=='anonymous'"
+        tal:attributes="action request/base">
+   <p class="userblock">
+    <b i18n:translate="">Login</b><br>
+    <input size="10" name="__login_name"><br>
+    <input size="10" type="password" name="__login_password"><br>
+    <input type="hidden" name="@action" value="Login">
+    <input type="checkbox" name="remember" id="remember">
+    <label for="remember" i18n:translate="">Remember me?</label><br>
+    <input type="submit" value="Login" i18n:attributes="value"><br>
+    <input type="hidden" name="__came_from" tal:attributes="value string:${request/base}${request/env/PATH_INFO}">
+    <span tal:replace="structure request/indexargs_form" />
+    <a href="user?@template=register"
+       tal:condition="python:request.user.hasPermission('Create', 'user')"
+     i18n:translate="">Register</a><br>
+    <a href="user?@template=forgotten" i18n:translate="">Lost&nbsp;your&nbsp;login?</a><br>
+   </p>
+  </form>
+
+  <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
+   <b i18n:translate="">Hello, <span i18n:name="user"
+    tal:replace="python:request.user.username.plain(escape=1)">username</span></b><br>
+   <a href="#" tal:attributes="href string:user${request/user/id}"
+    i18n:translate="">Your Details</a><br>
+   <a href="#" tal:attributes="href python:request.indexargs_url('',
+       {'@action':'logout'})" i18n:translate="">Logout</a>
+  </p>
+  <p class="userblock">
+   <b i18n:translate="">Help</b><br>
+   <a href="http://roundup.sourceforge.net/doc-1.0/"
+    i18n:translate="">Roundup docs</a>
+  </p>
+ </td>
+ <td>
+  <p tal:condition="options/error_message | nothing" class="error-message"
+     tal:repeat="m options/error_message" tal:content="structure m" />
+  <p tal:condition="options/ok_message | nothing" class="ok-message">
+    <span tal:repeat="m options/ok_message"
+       tal:content="structure string:$m <br/ > " />
+     <a class="form-small" tal:attributes="href request/current_url"
+        i18n:translate="">clear this message</a>
+  </p>
+ </td>
+</tr>
+<tr>
+ <td class="content" metal:define-slot="content">Page content goes here</td>
+</tr>
+
+</table>
+
+<pre tal:condition="request/form/debug | nothing" tal:content="request">
+</pre>
+
+</body>
+</html>
+</tal:block>
+
+<!--
+The following macros are intended to be used in search pages.
+
+The invoking context must define a "name" variable which names the
+property being searched.
+
+See issue.search.html in the classic template for examples.
+-->
+
+<!-- creates a th and a label: -->
+<th metal:define-macro="th_label"
+    tal:define="required required | python:[]"
+    tal:attributes="class python:(name in required) and 'required' or nothing">
+  <label tal:attributes="for name" tal:content="label" i18n:translate="">text</label>
+       <metal:x define-slot="behind_the_label" />
+</th>
+
+<td metal:define-macro="search_input">
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+</td>
+
+<td metal:define-macro="search_date">
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+  <a class="classhelp"
+        tal:attributes="href python:'''javascript:help_window('issue?@template=calendar&property=%s&form=itemSynopsis', 300, 200)'''%name">(cal)</a>
+</td>
+
+<td metal:define-macro="search_popup">
+  <!--
+    context needs to specify the popup "columns" as a comma-separated
+    string (eg. "id,title" or "id,name,description") as well as name
+  -->
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+  <span tal:replace="structure python:db.issue.classhelp(columns,
+                                      property=name)" />
+</td>
+
+<td metal:define-macro="search_select">
+  <select tal:attributes="name name; id name"
+          tal:define="value python:request.form.getvalue(name)">
+    <option value="" i18n:translate="">don't care</option>
+    <metal:slot define-slot="extra_options" />
+    <option value="" i18n:translate="" disabled="disabled">------------</option>
+    <option tal:repeat="s python:db[db_klass].list()"
+            tal:attributes="value s/id; selected python:value == s.id"
+            tal:content="python:s[db_content]"></option>
+  </select>
+</td>
+
+<!-- like search_select, but translates the further values.
+Could extend it (METAL 1.1 attribute "extend-macro")
+-->
+<td metal:define-macro="search_select_translated">
+  <select tal:attributes="name name; id name"
+          tal:define="value python:request.form.getvalue(name)">
+    <option value="" i18n:translate="">don't care</option>
+    <metal:slot define-slot="extra_options" />
+    <option value="" i18n:translate="" disabled="disabled">------------</option>
+    <option tal:repeat="s python:db[db_klass].list()"
+            tal:attributes="value s/id; selected python:value == s.id"
+                                               tal:content="python:s[db_content]"
+                                               i18n:translate=""></option>
+  </select>
+</td>
+
+<!-- currently, there is no convenient API to get a list of all roles -->
+<td metal:define-macro="search_select_roles"
+         tal:define="onchange onchange | nothing">
+  <select name=roles id=roles tal:attributes="onchange onchange">
+    <option value="" i18n:translate="">don't care</option>
+    <option value="" i18n:translate="" disabled="disabled">------------</option>
+    <option value="User">User</option>
+    <option value="Admin">Admin</option>
+    <option value="Anonymous">Anonymous</option>
+  </select>
+</td>
+
+<td metal:define-macro="search_multiselect">
+  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
+                         name name;
+                         id name">
+  <span tal:replace="structure python:db[db_klass].classhelp(db_content,
+                                        property=name, width='600')" />
+</td>
+
+<td metal:define-macro="search_checkboxes">
+ <ul class="search-checkboxes"
+     tal:define="value python:request.form.getvalue(name);
+                 values python:value and value.split(',') or []">
+ <li tal:repeat="s python:db[db_klass].list()">
+  <input type="checkbox" tal:attributes="name name; id string:$name-${s/id};
+    value s/id; checked python:s.id in values" />
+  <label tal:attributes="for string:$name-${s/id}"
+         tal:content="python:s[db_content]" />
+ </li>
+ <li metal:define-slot="no_value_item">
+  <input type="checkbox" value="-1" tal:attributes="name name;
+     id string:$name--1; checked python:value == '-1'" />
+  <label tal:attributes="for string:$name--1" i18n:translate="">no value</label>
+ </li>
+ </ul>
+</td>
+
+<td metal:define-macro="column_input">
+  <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"
+         tal:attributes="value name;
+                         checked python:name == sort_on">
+</td>
+
+<td metal:define-macro="group_input">
+  <input type="radio" name="@group"
+         tal:attributes="value name;
+                         checked python:name == group_on">
+</td>
+
+<!--
+The following macros are intended for user editing.
+
+The invoking context must define a "name" variable which names the
+property being searched; the "edit_ok" variable tells whether the
+current user is allowed to edit.
+
+See user.item.html in the classic template for examples.
+-->
+<script metal:define-macro="user_utils" type="text/javascript" src="@@file/user_utils.js"></script>
+
+<!-- src: value will be re-used for other input fields -->
+<input metal:define-macro="user_src_input"
+    type="text" tal:attributes="onblur python:edit_ok and 'split_name(this)';
+    id name; name name; value value; readonly not:edit_ok"
+    value="heinz.kunz">
+<!-- normal: no re-using -->
+<input metal:define-macro="user_normal_input" type="text"
+    tal:attributes="id name; name name; value value; readonly not:edit_ok"
+    value="heinz">
+<!-- password: type; no initial value -->
+    <input metal:define-macro="user_pw_input" type="password"
+    tal:attributes="id name; name name; readonly not:edit_ok" value="">
+    <input metal:define-macro="user_confirm_input" type="password"
+    tal:attributes="id name; name string:@confirm@$name; readonly not:edit_ok" value="">
+
diff --git a/share/roundup/templates/minimal/html/style.css b/share/roundup/templates/minimal/html/style.css
new file mode 100644 (file)
index 0000000..f7d7eb4
--- /dev/null
@@ -0,0 +1,423 @@
+/* main page styles */
+body.body {
+  font-family: sans-serif, Arial, Helvetica;
+  background-color: white;
+  color: #333;
+  margin: 0;
+}
+a[href]:hover {
+  color:blue;
+  text-decoration: underline;
+}
+a[href], a[href]:link {
+  color:blue;
+  text-decoration: none;
+}
+
+table.body {
+  border: 0;
+  padding: 0;
+  border-spacing: 0;
+  border-collapse: separate;
+}
+
+td.page-header-left {
+  padding: 5px;
+  border-bottom: 1px solid #444;
+}
+td.sidebar {
+  padding: 1px 0 0 1px;
+  white-space: nowrap;
+}
+
+/* don't display the sidebar when printing */
+@media print {
+    td.page-header-left {
+        display: none;
+    }
+    td.sidebar {
+        display: none;
+    }
+    .index-controls {
+        display: none;
+    }
+    #searchbox {
+        display: none;
+    }
+}
+
+td.page-header-top {
+  padding: 5px;
+  border-bottom: 1px solid #444;
+}
+#searchbox {
+    float: right;
+}
+
+div#body-title {
+  float: left;
+}
+
+
+div#searchbox {
+  float: right;
+  padding-top: 1em;
+}
+
+div#searchbox input#search-text {
+  width: 10em;
+}
+
+form {
+  margin: 0;
+}
+
+textarea {
+    font-family: monospace;
+}
+
+td.sidebar p.classblock {
+  padding: 2px 5px 2px 5px;
+  margin: 1px;
+  border: 1px solid #444;
+  background-color: #eee;
+}
+
+td.sidebar p.userblock {
+  padding: 2px 5px 2px 5px;
+  margin: 1px 1px 1px 1px;
+  border: 1px solid #444;
+  background-color: #eef;
+}
+
+.form-small {
+  padding: 0;
+  font-size: 75%;
+}
+
+
+td.content {
+  padding: 1px 5px 1px 5px;
+  vertical-align: top;
+  width: 100%;
+}
+
+td.date, th.date { 
+  white-space: nowrap;
+}
+
+p.ok-message {
+  background-color: #22bb22;
+  padding: 5px;
+  color: white;
+  font-weight: bold;
+}
+p.error-message {
+  background-color: #bb2222;
+  padding: 5px;
+  color: white;
+  font-weight: bold;
+}
+p.error-message a[href] {
+  color: white;
+  text-decoration: underline;
+}
+
+
+/* style for search forms */
+ul.search-checkboxes {
+    display: inline;
+    padding: none;
+    list-style: none;
+}
+ul.search-checkboxes > li {
+    display: inline;
+    padding-right: .5em;
+}
+
+
+/* style for forms */
+table.form {
+  padding: 2px;
+  border-spacing: 0;
+  border-collapse: separate;
+}
+
+table.form th {
+  color: #338;
+  text-align: right;
+  vertical-align: top;
+  font-weight: normal;
+  white-space: nowrap;
+}
+
+table.form th.header {
+  font-weight: bold;
+  background-color: #eef;
+  text-align: left;
+}
+
+table.form th.required {
+  font-weight: bold;
+}
+
+table.form td {
+  color: #333;
+  empty-cells: show;
+  vertical-align: top;
+}
+
+table.form td.optional {
+  font-weight: bold;
+  font-style: italic;
+}
+
+table.form td.html {
+  color: #777;
+}
+
+/* style for lists */
+table.list {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.list th {
+  padding: 0 4px 0 4px;
+  color: #404070;
+  background-color: #eef;
+  border: 1px solid white;
+  vertical-align: top;
+  empty-cells: show;
+}
+table.list th a[href]:hover { color: #404070 }
+table.list th a[href]:link { color: #404070 }
+table.list th a[href] { color: #404070 }
+table.list th.group {
+  background-color: #f4f4ff;
+  text-align: center;
+}
+
+table.list td {
+  padding: 0 4px 0 4px;
+  border: 1px solid white;
+  color: #404070;
+  background-color: #efefef;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+table.list tr.navigation th {
+  width: 33%;
+  border-style: hidden;
+  text-align: center;
+}
+table.list tr.navigation td {
+    border: none
+}
+table.list tr.navigation th:first-child {
+  text-align: left;
+}
+table.list tr.navigation th:last-child {
+  text-align: right;
+}
+
+
+/* style for message displays */
+table.messages {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.messages th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.messages th {
+  font-weight: bold;
+  color: black;
+  text-align: left;
+  border-bottom: 1px solid #afafaf;
+}
+
+table.messages td {
+  font-family: monospace;
+  background-color: #efefef;
+  border-bottom: 1px solid #afafaf;
+  color: black;
+  empty-cells: show;
+  border-right: 1px solid #afafaf;
+  vertical-align: top;
+  padding: 2px 5px 2px 5px;
+}
+
+table.messages td:first-child {
+  border-left: 1px solid #afafaf;
+  border-right: 1px solid #afafaf;
+}
+
+/* style for file displays */
+table.files {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.files th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.files th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+
+table.files td {
+  font-family: monospace;
+  empty-cells: show;
+}
+
+/* style for history displays */
+table.history {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.history th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+  font-size: 100%;
+}
+
+table.history th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+  font-size: 90%;
+}
+
+table.history td {
+  font-size: 90%;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+
+/* style for class list */
+table.classlist {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.classlist th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.classlist th {
+  font-weight: bold;
+  text-align: left;
+}
+
+
+/* style for class help display */
+table.classhelp {      /* the table-layout: fixed;        */ 
+  table-layout: fixed; /* compromises quality for speed   */
+  overflow: hidden;
+  font-size: .9em;
+  padding-bottom: 3em;
+}
+
+table.classhelp th {
+  font-weight: normal;
+  text-align: left;
+  color: #444;
+  background-color: #efefef;
+  border-bottom: 1px solid #afafaf;
+  border-top: 1px solid #afafaf;
+  text-transform: uppercase;
+  vertical-align: middle;
+  line-height:1.5em;
+}
+
+table.classhelp td {
+  vertical-align: middle;
+  padding-right: .2em;
+  border-bottom: 1px solid #efefef;
+  text-align: left;
+  empty-cells: show;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+
+table.classhelp tr:hover {
+  background-color: #eee;
+}
+
+label.classhelp-label {
+  cursor: pointer;
+}
+
+#classhelp-controls {
+  position: fixed;
+  display: block;
+  top: auto;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  padding: .5em;
+  border-top: 2px solid #444;
+  background-color: #eee;
+}
+
+#classhelp-controls input.apply {
+  width: 7em;
+  font-weight: bold;
+  margin-right: 2em;
+  margin-left: 2em;
+}
+
+#classhelp-controls input.preview {
+   margin-right: 3em;
+   margin-left: 1em;
+}
+
+/* style for "other" displays */
+table.otherinfo {
+  border-spacing: 0;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.otherinfo th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.otherinfo th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
diff --git a/share/roundup/templates/minimal/html/user.index.html b/share/roundup/templates/minimal/html/user.index.html
new file mode 100644 (file)
index 0000000..f0a84b8
--- /dev/null
@@ -0,0 +1,35 @@
+<!-- dollarId: user.index,v 1.3 2002/07/09 05:29:51 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title" i18n:translate="">User listing - <span
+ i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">User listing</span>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))"
+ i18n:translate="">You are not allowed to view this page.</span>
+
+<span tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')"
+ i18n:translate="">Please login with your username and password.</span>
+
+<table width="100%" tal:condition="context/is_view_ok" class="list">
+<tr>
+ <th i18n:translate="">Username</th>
+ <th i18n:translate="">Email address</th>
+</tr>
+<tal:block repeat="user context/list">
+ <tr tal:condition="user/is_view_ok"
+    tal:attributes="class python:['normal', 'alt'][repeat['user'].index%6/3]">
+ <td>
+  <a tal:attributes="href string:user${user/id}"
+     tal:content="user/username">username</a>
+ </td>
+ <td tal:content="python:user.address.email()">address</td>
+ </tr>
+</tal:block>
+</table>
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/user.item.html b/share/roundup/templates/minimal/html/user.item.html
new file mode 100644 (file)
index 0000000..bafccd2
--- /dev/null
@@ -0,0 +1,169 @@
+<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
+<tal:doc metal:use-macro="templates/page/macros/icing"
+define="edit_ok context/is_edit_ok"
+>
+<title metal:fill-slot="head_title">
+<tal:if condition="context/id" i18n:translate=""
+ >User <tal:x content="context/id" i18n:name="id"
+ />: <tal:x content="context/username" i18n:name="title"
+ /> - <tal:x content="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:if>
+<tal:if condition="not:context/id" i18n:translate=""
+ >New User - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
+/></tal:if>
+</title>
+<metal:slot fill-slot="more-javascript">
+<script metal:use-macro="templates/page/macros/user_utils"></script>
+<script type="text/javascript" src="@@file/help_controls.js"></script>
+</metal:slot>
+<tal:block metal:fill-slot="body_title"
+  define="edit_ok context/is_edit_ok">
+ <span tal:condition="python: not (context.id or edit_ok)"
+  tal:omit-tag="python:1" i18n:translate="">New User</span>
+ <span tal:condition="python: not context.id and edit_ok"
+  tal:omit-tag="python:1" i18n:translate="">New User Editing</span>
+ <span tal:condition="python: context.id and not edit_ok"
+  tal:omit-tag="python:1" i18n:translate="">User<tal:x
+  replace="context/id" i18n:name="id" /></span>
+ <span tal:condition="python: context.id and edit_ok"
+  tal:omit-tag="python:1" i18n:translate="">User<tal:x
+  replace="context/id" i18n:name="id" /> Editing</span>
+</tal:block>
+
+<td class="content" metal:fill-slot="content">
+
+<p tal:condition="python:not (context.is_view_ok()
+ or request.user.hasRole('Anonymous'))" i18n:translate="">
+ You are not allowed to view this page.</p>
+
+<p tal:condition="python:not context.is_view_ok()
+ and request.user.hasRole('Anonymous')" i18n:translate="">
+ Please login with your username and password.</p>
+
+<div tal:condition="context/is_view_ok">
+
+<form method="POST"
+      name="itemSynopsis"
+      tal:define="required python:'username address'.split()"
+      enctype="multipart/form-data"
+      tal:attributes="action context/designator;
+      onSubmit python:'return checkRequiredFields(\'%s\')'%'\', \''.join(required);
+      ">
+<table class="form" tal:define="
+  th_label templates/page/macros/th_label;
+  src_input templates/page/macros/user_src_input;
+  normal_input templates/page/macros/user_normal_input;
+  pw_input templates/page/macros/user_pw_input;
+  confirm_input templates/page/macros/user_confirm_input;
+  edit_ok context/is_edit_ok;
+  ">
+ <tr tal:define="name string:realname; label string:Name; value context/realname; edit_ok edit_ok">
+  <th metal:use-macro="th_label">Name</th>
+  <td><input name="realname" metal:use-macro="src_input"></td>
+ </tr>
+ <tr tal:define="name string:username; label string:Login Name; value context/username">
+   <th metal:use-macro="th_label">Login Name</th>
+   <td><input metal:use-macro="src_input"></td>
+ </tr>
+ <tal:if condition="edit_ok">
+ <tr tal:define="name string:password; label string:Login Password">
+  <th metal:use-macro="th_label">Login Password</th>
+  <td><input metal:use-macro="pw_input" type="password"></td>
+ </tr>
+ <tr tal:define="name string:password; label string:Confirm Password">
+  <th metal:use-macro="th_label">Confirm Password</th>
+  <td><input metal:use-macro="confirm_input" type="password"></td>
+ </tr>
+ </tal:if>
+ <tal:if condition="python:request.user.hasPermission('Web Roles')">
+ <tr tal:define="name string:roles; label string:Roles;">
+  <th><label for="roles" i18n:translate="">Roles</label></th>
+  <td tal:define="gips context/id">
+    <tal:subif condition=gips define="value context/roles">
+      <input metal:use-macro="normal_input">
+    </tal:subif>
+    <tal:subif condition="not:gips" define="value db/config/NEW_WEB_USER_ROLES">
+      <input metal:use-macro="normal_input">
+    </tal:subif>
+   <tal:block i18n:translate="">(to give the user more than one role,
+    enter a comma,separated,list)</tal:block>
+  </td>
+ </tr>
+ </tal:if>
+
+ <tr tal:define="name string:phone; label string:Phone; value context/phone">
+  <th metal:use-macro="th_label">Phone</th>
+  <td><input name="phone" metal:use-macro="normal_input"></td>
+ </tr>
+
+ <tr tal:define="name string:organisation; label string:Organisation; value context/organisation">
+  <th metal:use-macro="th_label">Organisation</th>
+  <td><input name="organisation" metal:use-macro="normal_input"></td>
+ </tr>
+
+ <tr tal:condition="python:edit_ok or context.timezone"
+     tal:define="name string:timezone; label string:Timezone; value context/timezone">
+  <th metal:use-macro="th_label">Timezone</th>
+  <td><input name="timezone" metal:use-macro="normal_input">
+   <tal:block tal:condition="edit_ok" i18n:translate="">(this is a numeric hour offset, the default is
+    <span tal:replace="db/config/DEFAULT_TIMEZONE" i18n:name="zone"
+    />)</tal:block>
+  </td>
+ </tr>
+
+ <tr tal:define="name string:address; label string:E-mail address; value context/address">
+  <th metal:use-macro="th_label">E-mail address</th>
+  <td tal:define="mailto python:context.address.field(id='address');
+         mklink python:mailto and not edit_ok">
+      <a href="mailto:calvin@the-z.org"
+                 tal:attributes="href string:mailto:$value"
+                 tal:content="value"
+          tal:condition="python:mklink">calvin@the-z.org</a>
+      <tal:if condition=edit_ok>
+      <input metal:use-macro="src_input" value="calvin@the-z.org">
+      </tal:if>
+      &nbsp;
+  </td>
+ </tr>
+
+ <tr>
+  <th><label for="alternate_addresses" i18n:translate="">Alternate E-mail addresses<br>One address per line</label></th>
+  <td>
+    <textarea rows=5 cols=40 tal:replace="structure context/alternate_addresses/multiline">nobody@nowhere.org
+anybody@everywhere.net
+(alternate_addresses)
+    </textarea>
+  </td>
+ </tr>
+
+ <tr tal:condition="edit_ok">
+  <td>
+   &nbsp;
+   <input type="hidden" name="@template" value="item">
+   <input type="hidden" name="@required" value="username,address"
+          tal:attributes="value python:','.join(required)">
+  </td>
+  <td><input type="submit" value="save" tal:replace="structure context/submit"><!--submit button here-->
+    <input type=reset>
+  </td>
+ </tr>
+</table>
+</form>
+
+<tal:block tal:condition="not:context/id" i18n:translate="">
+<table class="form">
+<tr>
+ <td>Note:&nbsp;</td>
+ <th class="required">highlighted</th>
+ <td>&nbsp;fields are required.</td>
+</tr>
+</table>
+</tal:block>
+
+<tal:block tal:condition="context/id" tal:replace="structure context/history" />
+
+</div>
+
+</td>
+
+</tal:doc>
diff --git a/share/roundup/templates/minimal/html/user.register.html b/share/roundup/templates/minimal/html/user.register.html
new file mode 100644 (file)
index 0000000..7e7a5d3
--- /dev/null
@@ -0,0 +1,73 @@
+<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title"
+ i18n:translate="">Registering with <span i18n:name="tracker"
+ tal:replace="db/config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Registering with <span i18n:name="tracker"
+ tal:replace="db/config/TRACKER_NAME" /></span>
+<td class="content" metal:fill-slot="content">
+
+<tal:block tal:define=" editok python:request.user.username=='anonymous' and
+           request.user.hasPermission('Web Registration')">
+
+<span tal:condition="python:not (editok or request.user.hasRole('Anonymous'))"
+ i18n:translate="">You are not allowed to view this page.</span>
+
+<span tal:condition="python:not editok and request.user.hasRole('Anonymous')"
+ i18n:translate="">Please login with your username and password.</span>
+
+<tal:block tal:condition="editok">
+<form method="POST" onSubmit="return submit_once()" enctype="multipart/form-data">
+<input type="hidden" name=":template" value="register">
+<input type="hidden" name=":required" value="username">
+<input type="hidden" name=":required" value="password">
+<input type="hidden" name=":required" value="address">
+
+<table class="form">
+ <tr>
+  <th i18n:translate="">Login Name</th>
+  <td tal:content="structure context/username/field">username</td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Login Password</th>
+  <td tal:content="structure context/password/field">password</td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Confirm Password</th>
+  <td tal:content="structure context/password/confirm">password</td>
+ </tr>
+ <tr tal:condition="python:request.user.hasPermission('Web Roles')">
+  <th i18n:translate="">Roles</th>
+  <td tal:condition="exists:item"
+      tal:content="structure context/roles/field">roles</td>
+  <td tal:condition="not:exists:item">
+   <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
+  </td>
+ </tr>
+ <tr>
+  <th i18n:translate="">E-mail address</th>
+  <td tal:content="structure context/address/field">address</td>
+ </tr>
+ <tr>
+  <th i18n:translate="">Alternate E-mail addresses<br>One address per line</th>
+  <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
+ </tr>
+
+ <tr>
+  <td>&nbsp;</td>
+  <td>
+   <input type="hidden" name=":action" value="register">
+   <input type="submit" name="submit" value="Register" i18n:attributes="value">
+  </td>
+ </tr>
+</table>
+</form>
+
+</tal:block>
+
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/share/roundup/templates/minimal/html/user.rego_progress.html b/share/roundup/templates/minimal/html/user.rego_progress.html
new file mode 100644 (file)
index 0000000..4d6bfe4
--- /dev/null
@@ -0,0 +1,16 @@
+<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title"
+ i18n:translate="">Registration in progress - <span i18n:name="tracker"
+ tal:replace="config/TRACKER_NAME" /></title>
+<span metal:fill-slot="body_title" tal:omit-tag="python:1"
+ i18n:translate="">Registration in progress...</span>
+<td class="content" metal:fill-slot="content">
+
+<p i18n:translate="">You will shortly receive an email
+to confirm your registration. To complete the registration process,
+visit the link indicated in the email.
+</p>
+
+</td>
+</tal:block>
diff --git a/share/roundup/templates/minimal/initial_data.py b/share/roundup/templates/minimal/initial_data.py
new file mode 100644 (file)
index 0000000..28bfefe
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# TRACKER DATABASE INITIALIZATION
+#
+
+# create the two default users
+user = db.getclass('user')
+user.create(username="admin", password=adminpw,
+    address=admin_email, roles='Admin')
+user.create(username="anonymous", roles='Anonymous')
+
+# add any additional database creation steps here - but only if you
+# haven't initialised the database with the admin "initialise" command
+
+# vim: set et sts=4 sw=4 :
diff --git a/share/roundup/templates/minimal/schema.py b/share/roundup/templates/minimal/schema.py
new file mode 100644 (file)
index 0000000..909c9b1
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# TRACKER SCHEMA
+#
+
+# Class automatically gets these properties:
+#   creation = Date()
+#   activity = Date()
+#   creator = Link('user')
+#   actor = Link('user')
+
+# The "Minimal" template gets only one class, the required "user"
+# class. That's it. And even that has the bare minimum of properties.
+
+# Note: roles is a comma-separated string of Role names
+user = Class(db, "user", username=String(), password=Password(),
+    address=String(), alternate_addresses=String(), roles=String())
+user.setkey("username")
+#
+# TRACKER SECURITY SETTINGS
+#
+# See the configuration and customisation document for information
+# about security setup.
+
+#
+# REGULAR USERS
+#
+# Give the regular users access to the web and email interface
+db.security.addPermissionToRole('User', 'Web Access')
+db.security.addPermissionToRole('User', 'Email Access')
+
+# May users view other user information?
+# Comment these lines out if you don't want them to
+db.security.addPermissionToRole('User', 'View', 'user')
+
+# Users should be able to edit their own details -- this permission is
+# limited to only the situation where the Viewed or Edited item is their own.
+def own_record(db, userid, itemid):
+    '''Determine whether the userid matches the item being accessed.'''
+    return userid == itemid
+p = db.security.addPermission(name='View', klass='user', check=own_record,
+    description="User is allowed to view their own user details")
+db.security.addPermissionToRole('User', p)
+p = db.security.addPermission(name='Edit', klass='user', check=own_record,
+    description="User is allowed to edit their own user details")
+db.security.addPermissionToRole('User', p)
+
+#
+# ANONYMOUS USER PERMISSIONS
+#
+# Let anonymous users access the web interface. Note that almost all
+# trackers will need this Permission. The only situation where it's not
+# required is in a tracker that uses an HTTP Basic Authenticated front-end.
+db.security.addPermissionToRole('Anonymous', 'Web Access')
+
+# Let anonymous users access the email interface (note that this implies
+# that they will be registered automatically, hence they will need the
+# "Create" user Permission below)
+db.security.addPermissionToRole('Anonymous', 'Email Access')
+
+# Assign the appropriate permissions to the anonymous user's
+# Anonymous Role. Choices here are:
+# - Allow anonymous users to register
+db.security.addPermissionToRole('Anonymous', 'Create', 'user')
+
+# vim: set et sts=4 sw=4 :
diff --git a/templates/classic/.cvsignore b/templates/classic/.cvsignore
deleted file mode 100644 (file)
index d90d51d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-*.pyc
-*.pyo
-htmlbase.py
-*.cover
diff --git a/templates/classic/TEMPLATE-INFO.txt b/templates/classic/TEMPLATE-INFO.txt
deleted file mode 100644 (file)
index 1c20d54..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-Name: classic
-Description: This is a generic issue tracker that may be used to track bugs,
-             feature requests, project issues or any number of other types
-             of issues. Most users of Roundup will find that this template
-             suits them, with perhaps a few customisations.
-Intended-For: All first-time Roundup users
-
diff --git a/templates/classic/detectors/.cvsignore b/templates/classic/detectors/.cvsignore
deleted file mode 100644 (file)
index 4162d5e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-*.pyc
-*.pyo
-*.cover
diff --git a/templates/classic/detectors/messagesummary.py b/templates/classic/detectors/messagesummary.py
deleted file mode 100644 (file)
index def2e82..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#$Id: messagesummary.py,v 1.2 2007-04-03 06:47:21 a1s Exp $
-
-from roundup.mailgw import parseContent
-
-def summarygenerator(db, cl, nodeid, newvalues):
-    ''' If the message doesn't have a summary, make one for it.
-    '''
-    if newvalues.has_key('summary') or not newvalues.has_key('content'):
-        return
-
-    summary, content = parseContent(newvalues['content'], config=db.config)
-    newvalues['summary'] = summary
-
-
-def init(db):
-    # fire before changes are made
-    db.msg.audit('create', summarygenerator)
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/detectors/nosyreaction.py b/templates/classic/detectors/nosyreaction.py
deleted file mode 100644 (file)
index c732fd0..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-#
-# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
-# This module is free software, and you may redistribute it and/or modify
-# under the same terms as Python, so long as this copyright message and
-# disclaimer are retained in their original form.
-#
-# IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
-# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
-# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
-# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE.  THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
-# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
-# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
-# 
-#$Id: nosyreaction.py,v 1.4 2005-04-04 08:47:14 richard Exp $
-
-import sets
-
-from roundup import roundupdb, hyperdb
-
-def nosyreaction(db, cl, nodeid, oldvalues):
-    ''' A standard detector is provided that watches for additions to the
-        "messages" property.
-        
-        When a new message is added, the detector sends it to all the users on
-        the "nosy" list for the issue that are not already on the "recipients"
-        list of the message.
-        
-        Those users are then appended to the "recipients" property on the
-        message, so multiple copies of a message are never sent to the same
-        user.
-        
-        The journal recorded by the hyperdatabase on the "recipients" property
-        then provides a log of when the message was sent to whom. 
-    '''
-    # send a copy of all new messages to the nosy list
-    for msgid in determineNewMessages(cl, nodeid, oldvalues):
-        try:
-            cl.nosymessage(nodeid, msgid, oldvalues)
-        except roundupdb.MessageSendError, message:
-            raise roundupdb.DetectorError, message
-
-def determineNewMessages(cl, nodeid, oldvalues):
-    ''' Figure a list of the messages that are being added to the given
-        node in this transaction.
-    '''
-    messages = []
-    if oldvalues is None:
-        # the action was a create, so use all the messages in the create
-        messages = cl.get(nodeid, 'messages')
-    elif oldvalues.has_key('messages'):
-        # the action was a set (so adding new messages to an existing issue)
-        m = {}
-        for msgid in oldvalues['messages']:
-            m[msgid] = 1
-        messages = []
-        # figure which of the messages now on the issue weren't there before
-        for msgid in cl.get(nodeid, 'messages'):
-            if not m.has_key(msgid):
-                messages.append(msgid)
-    return messages
-
-def updatenosy(db, cl, nodeid, newvalues):
-    '''Update the nosy list for changes to the assignedto
-    '''
-    # nodeid will be None if this is a new node
-    current_nosy = sets.Set()
-    if nodeid is None:
-        ok = ('new', 'yes')
-    else:
-        ok = ('yes',)
-        # old node, get the current values from the node if they haven't
-        # changed
-        if not newvalues.has_key('nosy'):
-            nosy = cl.get(nodeid, 'nosy')
-            for value in nosy:
-                current_nosy.add(value)
-
-    # if the nosy list changed in this transaction, init from the new value
-    if newvalues.has_key('nosy'):
-        nosy = newvalues.get('nosy', [])
-        for value in nosy:
-            if not db.hasnode('user', value):
-                continue
-            current_nosy.add(value)
-
-    new_nosy = sets.Set(current_nosy)
-
-    # add assignedto(s) to the nosy list
-    if newvalues.has_key('assignedto') and newvalues['assignedto'] is not None:
-        propdef = cl.getprops()
-        if isinstance(propdef['assignedto'], hyperdb.Link):
-            assignedto_ids = [newvalues['assignedto']]
-        elif isinstance(propdef['assignedto'], hyperdb.Multilink):
-            assignedto_ids = newvalues['assignedto']
-        for assignedto_id in assignedto_ids:
-            new_nosy.add(assignedto_id)
-
-    # see if there's any new messages - if so, possibly add the author and
-    # recipient to the nosy
-    if newvalues.has_key('messages'):
-        if nodeid is None:
-            ok = ('new', 'yes')
-            messages = newvalues['messages']
-        else:
-            ok = ('yes',)
-            # figure which of the messages now on the issue weren't
-            oldmessages = cl.get(nodeid, 'messages')
-            messages = []
-            for msgid in newvalues['messages']:
-                if msgid not in oldmessages:
-                    messages.append(msgid)
-
-        # configs for nosy modifications
-        add_author = getattr(db.config, 'ADD_AUTHOR_TO_NOSY', 'new')
-        add_recips = getattr(db.config, 'ADD_RECIPIENTS_TO_NOSY', 'new')
-
-        # now for each new message:
-        msg = db.msg
-        for msgid in messages:
-            if add_author in ok:
-                authid = msg.get(msgid, 'author')
-                new_nosy.add(authid)
-
-            # add on the recipients of the message
-            if add_recips in ok:
-                for recipient in msg.get(msgid, 'recipients'):
-                    new_nosy.add(recipient)
-
-    if current_nosy != new_nosy:
-        # that's it, save off the new nosy list
-        newvalues['nosy'] = list(new_nosy)
-
-def init(db):
-    db.issue.react('create', nosyreaction)
-    db.issue.react('set', nosyreaction)
-    db.issue.audit('create', updatenosy)
-    db.issue.audit('set', updatenosy)
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/detectors/statusauditor.py b/templates/classic/detectors/statusauditor.py
deleted file mode 100644 (file)
index 75e4962..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (c) 2002 ekit.com Inc (http://www.ekit-inc.com/)
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-#   The above copyright notice and this permission notice shall be included in
-#   all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-#$Id: statusauditor.py,v 1.5 2004-03-27 00:01:48 richard Exp $
-
-def chatty(db, cl, nodeid, newvalues):
-    ''' If the issue is currently 'unread', 'resolved', 'done-cbb' or None,
-        then set it to 'chatting'
-    '''
-    # don't fire if there's no new message (ie. chat)
-    if not newvalues.has_key('messages'):
-        return
-    if newvalues['messages'] == cl.get(nodeid, 'messages'):
-        return
-
-    # get the chatting state ID
-    try:
-        chatting_id = db.status.lookup('chatting')
-    except KeyError:
-        # no chatting state, ignore all this stuff
-        return
-
-    # get the current value
-    current_status = cl.get(nodeid, 'status')
-
-    # see if there's an explicit change in this transaction
-    if newvalues.has_key('status'):
-        # yep, skip
-        return
-
-    # determine the id of 'unread', 'resolved' and 'chatting'
-    fromstates = []
-    for state in 'unread resolved done-cbb'.split():
-        try:
-            fromstates.append(db.status.lookup(state))
-        except KeyError:
-            pass
-
-    # ok, there's no explicit change, so check if we are in a state that
-    # should be changed
-    if current_status in fromstates + [None]:
-        # yep, we're now chatting
-        newvalues['status'] = chatting_id
-
-
-def presetunread(db, cl, nodeid, newvalues):
-    ''' Make sure the status is set on new issues
-    '''
-    if newvalues.has_key('status') and newvalues['status']:
-        return
-
-    # get the unread state ID
-    try:
-        unread_id = db.status.lookup('unread')
-    except KeyError:
-        # no unread state, ignore all this stuff
-        return
-
-    # ok, do it
-    newvalues['status'] = unread_id
-
-
-def init(db):
-    # fire before changes are made
-    db.issue.audit('set', chatty)
-    db.issue.audit('create', presetunread)
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/detectors/userauditor.py b/templates/classic/detectors/userauditor.py
deleted file mode 100644 (file)
index fc71a1c..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net)
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-#   The above copyright notice and this permission notice shall be included in
-#   all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-#$Id: userauditor.py,v 1.9 2007-09-12 21:11:13 jpend Exp $
-
-import re
-
-# regular expression thanks to: http://www.regular-expressions.info/email.html
-# this is the "99.99% solution for syntax only".
-email_regexp = (r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*", r"(localhost|(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]))")
-email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
-email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
-
-def valid_address(address):
-    ''' If we see an @-symbol in the address then check against the full
-        RFC syntax. Otherwise it is a local-only address so only check
-        the local part of the RFC syntax.
-    '''
-    if '@' in address:
-        return email_rfc.match(address)
-    else:
-        return email_local.match(address)
-
-def get_addresses(user):
-    ''' iterate over all known addresses in a newvalues dict
-        this takes of the address/alterate_addresses handling
-    '''
-    if user.has_key('address'):
-        yield user['address']
-    if user.get('alternate_addresses', None):
-        for address in user['alternate_addresses'].split('\n'):
-            yield address
-
-def audit_user_fields(db, cl, nodeid, newvalues):
-    ''' Make sure user properties are valid.
-
-        - email address is syntactically valid
-        - email address is unique
-        - roles specified exist
-        - timezone is valid
-    '''
-
-    for address in get_addresses(newvalues):
-        if not valid_address(address):
-            raise ValueError, 'Email address syntax is invalid'
-
-        check_main = db.user.stringFind(address=address)
-        # make sure none of the alts are owned by anyone other than us (x!=nodeid)
-        check_alts = [x for x in db.user.filter(None, {'alternate_addresses' : address}) if x != nodeid]
-        if check_main or check_alts:
-            raise ValueError, 'Email address %s already in use' % address
-
-    for rolename in [r.lower().strip() for r in newvalues.get('roles', '').split(',')]:
-            if rolename and not db.security.role.has_key(rolename):
-                raise ValueError, 'Role "%s" does not exist'%rolename
-
-    tz = newvalues.get('timezone', None)
-    if tz:
-        # if they set a new timezone validate the timezone by attempting to
-        # use it before we store it to the db.
-        import roundup.date
-        import datetime
-        try:
-            TZ = roundup.date.get_timezone(tz)
-            dt = datetime.datetime.now()
-            local = TZ.localize(dt).utctimetuple()
-        except IOError:
-            raise ValueError, 'Timezone "%s" does not exist' % tz
-        except ValueError:
-            raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz
-
-def init(db):
-    # fire before changes are made
-    db.user.audit('set', audit_user_fields)
-    db.user.audit('create', audit_user_fields)
-
-# vim: sts=4 sw=4 et si
diff --git a/templates/classic/extensions/README.txt b/templates/classic/extensions/README.txt
deleted file mode 100644 (file)
index ff4dff3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-This directory is for tracker extensions:
-
-- CGI Actions
-- Templating functions
-
-See the customisation doc for more information.
diff --git a/templates/classic/html/_generic.404.html b/templates/classic/html/_generic.404.html
deleted file mode 100644 (file)
index 71c9e0e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
-<head>
-<title>Item Not Found</title>
-</head>
-
-<body>
-There is no <span tal:content="context/_classname" /> with id <span tal:content="context/id"/>
-</body>
-</html>
diff --git a/templates/classic/html/_generic.calendar.html b/templates/classic/html/_generic.calendar.html
deleted file mode 100644 (file)
index 0f9cf40..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<!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" />
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" />
-  <title tal:content="string:Roundup Calendar"></title>
-  <script language="Javascript"
-          type="text/javascript"
-          tal:content="structure string:
-          // this is the name of the field in the original form that we're working on
-          form  = window.opener.document.${request/form/form/value};
-          field = '${request/form/property/value}';" >
-  </script>
- </head>
- <body class="body"
-       tal:content="structure python:utils.html_calendar(request)">
- </body>
-</html>
diff --git a/templates/classic/html/_generic.collision.html b/templates/classic/html/_generic.collision.html
deleted file mode 100644 (file)
index 2a2768a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> Edit Collision - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<tal:block metal:fill-slot="body_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> Edit Collision</tal:block>
-
-<td class="content" metal:fill-slot="content" i18n:translate="
-  There has been a collision. Another user updated this node
-  while you were editing. Please <a href='${context}'>reload</a>
-  the node and review your edits.
-"><span tal:replace="context/designator" i18n:name="context" />
-</td>
-</tal:block>
diff --git a/templates/classic/html/_generic.help-empty.html b/templates/classic/html/_generic.help-empty.html
deleted file mode 100644 (file)
index 65469fc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<html>
-  <head>
-    <title>Empty page (no search performed yet)</title>
-  </head>
-  <body>
-    <p i18n:translate="">Please specify your search parameters!</p>
-  </body>
-</html>
diff --git a/templates/classic/html/_generic.help-list.html b/templates/classic/html/_generic.help-list.html
deleted file mode 100644 (file)
index 66cbb90..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<!-- $Id: _generic.help-list.html,v 1.2 2008-03-01 08:18:07 richard Exp $ vim: sw=2 ts=8 et
---><html tal:define="vok context/is_view_ok">
-  <head>
-    <title>Search result for user helper</title>
-    <link rel="stylesheet" type="text/css" href="@@file/style.css" />
-    <script language="Javascript" type="text/javascript"
-        tal:content="structure string:<!--
-        // this is the name of the field in the original form that we're working on
-        form  = parent.opener.document.${request/form/form/value};
-        field  = '${request/form/property/value}';
-    //-->"></script>
-    <script src="@@file/help_controls.js" type="text/javascript"></script>
-<script type="text/javascript"><!--
-var text_field = parent.submit.document.frm_help.text_preview;
-//--></script>
-  </head>
-  <body>
-    <pre tal:content="request/env/QUERY_STRING" tal:condition=false />
-
-  <p tal:condition="not:vok" i18n:translate="">You are not
-  allowed to view this page.</p>
-
-  <tal:if condition="context/is_view_ok">
-  <tal:def define="batch request/batch;">
-  <form name=dummyform>
-    <table width="100%"
-      tal:define="template string:help-list"
-      metal:use-macro="templates/help/macros/batch_navi"
-      >
-      <tr class="navigation">
-       <th>
-        <a href="#">&lt;&lt; previous</a>
-       </th>
-       <th i18n:translate="">1..25 out of 50
-       </th>
-       <th>
-        <a href="#">next &gt;&gt;</a>
-       </th>
-      </tr>
-     </table>
-
-  <form name=dummyform>
-  <table class="classhelp"
-    tal:define="
-       props python:request.form['properties'].value.split(',');
-       legend templates/help/macros/legend;
-    "><thead>
-      <tr metal:use-macro="legend">
-         <th>&nbsp;<b>x</b></th>
-         <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
-       </tr>
-     </thead>
-     <tfoot tal:condition=true>
-       <tr metal:use-macro="legend" />
-     </tfoot>
-     <tbody>
-       <tr tal:repeat="item batch">
-         <tal:block tal:define="attr python:item[props[0]]" >
-           <td>
-             <input name="check"
-             onclick="switch_val(text_field, this);" type="checkbox"
-             tal:attributes="value attr; id string:id_$attr" />
-             </td>
-             <td tal:repeat="prop props">
-                 <label class="classhelp-label"
-                        tal:attributes="for string:id_$attr"
-                        tal:content="python:item[prop]"></label>
-             </td>
-           </tal:block>
-         </tr>
-       </tbody>
-     </table>
-   </form>
-     </tal:def>
-     </tal:if>
-     
-     <pre tal:content=request tal:condition=false />
-     <script type="text/javascript"><!--
-       parent.submit.document.frm_help.cb_listpresent.checked=true;
-       reviseList_framed(document.dummyform, text_field)
-     //--></script>
-  </body>
-</html>
diff --git a/templates/classic/html/_generic.help-search.html b/templates/classic/html/_generic.help-search.html
deleted file mode 100644 (file)
index 01d657e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-  <head>
-    <title>Frame for search input fields</title>
-  </head>
-  <body>
-    <p i18n:translate="">Generic template
-    <span tal:replace="request/template" i18n:name="template">help-search</span>
-    or version for class
-    <span tal:replace="request/classname" i18n:name="classname">user</span>
-    is not yet implemented</p>
-  </body>
-</html>
-
diff --git a/templates/classic/html/_generic.help-submit.html b/templates/classic/html/_generic.help-submit.html
deleted file mode 100644 (file)
index b13aa4a..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<html>
-  <head>
-      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
-      <meta http-equiv="Content-Type"
-       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
-      <tal:block tal:condition="python:request.form.has_key('property')">
-      <title>Generic submit page for framed helper windows</title>
-      <script language="Javascript" type="text/javascript"
-          tal:content="structure string:<!--
-// this is the name of the field in the original form that we're working on
-form  = parent.opener.document.${request/form/form/value};
-callingform=form
-field  = '${request/form/property/value}';
-var listform = null
-function listPresent() {
-  return document.frm_help.cb_listpresent.checked
-}
-function getListForm() {
-  if (listPresent()) {
-    return parent.list.document.forms.dummyform
-  } else {
-    return null
-  }
-}
-
-
-function checkListForm() {
-  // global listform
-  if (listform != null)
-    if (parent.list.document.dummyform) {
-      listform = parent.list.document.dummyform
-      alert(listform)
-    }
-
-  var bol= listform != null
-  alert('checkListForm: bol='+bol)
-  return bol
-}
-//-->">
-      </script>
-      <script src="@@file/help_controls.js" type="text/javascript"></script>
-      </tal:block>
-  </head>
- <body class="body" onload="parent.focus();" id="submit">
- <pre tal:content="request/env/QUERY_STRING" tal:condition=false />
- <form name="frm_help"
-       tal:define="batch request/batch;
-       props python:request.form['properties'].value.split(',')"
-       class="help-submit"
-       id="classhelp-controls">
-     <div style="width:100%;text-align:left;margin-bottom:0.2em">
-       <input type="text" name="text_preview" size="24" class="preview"
-       onchange="f=getListForm();if(f){ reviseList_framed(f, this)};"
-       />
-     </div>
-     <input type=checkbox name="cb_listpresent" readonly="readonly" style="display:none">
-     <input type="button" id="btn_cancel"
-            value=" Cancel " onclick="parent.close();return false;"
-            i18n:attributes="value" />
-     <input type="reset" id="btn_reset"
-     onclick="text_field.value=original_field;f=getListForm();if (f) {reviseList_framed(f, this)};return false"
-            />
-     <input type="submit" id="btn_apply" class="apply"
-            value=" Apply " onclick="callingform[field].value=text_field.value; parent.close();"
-            i18n:attributes="value" />
- </form>
- <script type="text/javascript"><!--
-var text_field = document.frm_help.text_preview;
-original_field=form[field].value;
-text_field.value=original_field;
-//--></script>
- </body>
-</html>
diff --git a/templates/classic/html/_generic.help.html b/templates/classic/html/_generic.help.html
deleted file mode 100644 (file)
index 069c0a6..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html tal:define="property request/form/property/value" >
-  <head>
-      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
-      <meta http-equiv="Content-Type"
-       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
-      <tal:block tal:condition="python:request.form.has_key('property')">
-      <title i18n:translate=""><tal:x i18n:name="property"
-       tal:content="property" i18n:translate="" /> help - <span i18n:name="tracker"
-       tal:replace="config/TRACKER_NAME" /></title>
-      <script language="Javascript" type="text/javascript"
-          tal:content="structure string:
-          // this is the name of the field in the original form that we're working on
-          form  = window.opener.document.${request/form/form/value};
-          field  = '${request/form/property/value}';">
-      </script>
-      <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="batch request/batch;
-                   props python:request.form['properties'].value.split(',')">
-
-     <div id="classhelp-controls">
-       <!--input type="button" name="btn_clear"
-              value="Clear" onClick="clearList()"/ -->
-       <input type="text" name="text_preview" size="24" class="preview"
-              onchange="reviseList(this.value);"/>
-       <input type="button" name="btn_reset"
-              value=" Cancel " onclick="resetList(); window.close();"
-              i18n:attributes="value" />
-       <input type="button" name="btn_apply" class="apply"
-              value=" Apply " onclick="updateList(); window.close();"
-              i18n:attributes="value" />
-     </div>
-     <table width="100%">
-      <tr class="navigation">
-       <th>
-        <a tal:define="prev batch/previous" tal:condition="prev"
-           tal:attributes="href python:request.indexargs_url(request.classname,
-           {'@template':'help', 'property': request.form['property'].value,
-            'properties': request.form['properties'].value,
-            'form': request.form['form'].value,
-            'type': request.form['type'].value,
-            '@startwith':prev.first, '@pagesize':prev.size})"
-           i18n:translate="" >&lt;&lt; previous</a>
-        &nbsp;
-       </th>
-       <th i18n:translate=""><span tal:replace="batch/start" i18n:name="start"
-        />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
-        /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
-        />
-       </th>
-       <th>
-        <a tal:define="next batch/next" tal:condition="next"
-           tal:attributes="href python:request.indexargs_url(request.classname,
-           {'@template':'help', 'property': request.form['property'].value,
-            'properties': request.form['properties'].value,
-            'form': request.form['form'].value,
-            'type': request.form['type'].value,
-            '@startwith':next.first, '@pagesize':next.size})"
-           i18n:translate="" >next &gt;&gt;</a>
-        &nbsp;
-       </th>
-      </tr>
-     </table>
-
-     <table class="classhelp">
-       <tr>
-           <th>&nbsp;<b>x</b></th>
-           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
-       </tr>
-       <tr tal:repeat="item batch">
-         <tal:block tal:define="attr python:item[props[0]]" >
-           <td>
-             <input name="check"
-                 onclick="updatePreview();"
-                 tal:attributes="type python:request.form['type'].value;
-                                 value attr; id string:id_$attr" />
-             </td>
-             <td tal:repeat="prop props">
-                 <label class="classhelp-label"
-                        tal:attributes="for string:id_$attr"
-                        tal:content="python:item[prop]"></label>
-             </td>
-           </tal:block>
-       </tr>
-       <tr>
-           <th>&nbsp;<b>x</b></th>
-           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
-       </tr>
-     </table>
-
- </form>
- </body>
-</html>
diff --git a/templates/classic/html/_generic.index.html b/templates/classic/html/_generic.index.html
deleted file mode 100644 (file)
index a41ab0a..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
-
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<tal:block metal:fill-slot="body_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok()
- or request.user.hasRole('Anonymous'))"
- tal:omit-tag="python:1" i18n:translate=""
->You are not allowed to view this page.</span>
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())
- and request.user.hasRole('Anonymous')"
- tal:omit-tag="python:1" i18n:translate=""
->Please login with your username and password.</span>
-
-<tal:block tal:condition="context/is_edit_ok">
-<tal:block i18n:translate="">
-<p class="form-help">
- You may edit the contents of the
- <span tal:replace="request/classname" i18n:name="classname"/>
- class using this form. Commas, newlines and double quotes (") must be
- handled delicately. You may include commas and newlines by enclosing the
- values in double-quotes ("). Double quotes themselves must be quoted by
- doubling ("").
-</p>
-
-<p class="form-help">
- Multilink properties have their multiple values colon (":") separated
- (... ,"one:two:three", ...)
-</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>
-</tal:block>
-<form onSubmit="return submit_once()" method="POST"
-      tal:attributes="action context/designator">
-<textarea rows="15" style="width:90%" name="rows" tal:content="context/csv"></textarea>
-<br>
-<input type="hidden" name="@action" value="editCSV">
-<input type="submit" value="Edit Items" i18n:attributes="value">
-</form>
-</tal:block>
-
-<table tal:condition="context/is_only_view_ok" width="100%" class="list">
- <tr>
-  <th tal:repeat="property context/propnames" tal:content="property">&nbsp;</th>
- </tr>
- <tal:block repeat="item context/list">
- <tr tal:condition="item/is_view_ok"
-     tal:attributes="class python:['normal', 'alt'][repeat['item'].index%6/3]">
-  <td tal:repeat="property context/propnames"
-   tal:content="python: item[property] or default"
-  >&nbsp;</td>
- </tr>
- </tal:block>
-</table>
-
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/_generic.item.html b/templates/classic/html/_generic.item.html
deleted file mode 100644 (file)
index d9b98ae..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<tal:block metal:fill-slot="body_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<div tal:condition="context/is_view_ok">
-
-<form method="POST" onSubmit="return submit_once()"
-      enctype="multipart/form-data" tal:condition="context/is_view_ok"
-      tal:attributes="action context/designator">
-
-<input type="hidden" name="@template" value="item">
-
-<table class="form">
-
-<tr tal:repeat="prop python:db[context._classname].properties()">
- <tal:block tal:condition="python:prop._name not in ('id',
-   'creator', 'creation', 'actor', 'activity')">
-  <th tal:content="prop/_name"></th>
-  <td tal:content="structure python:context[prop._name].field()"></td>
- </tal:block>
-</tr>
-<tr>
- <td>&nbsp;</td>
- <td colspan=3 tal:content="structure context/submit">
-  submit button will go here
- </td>
-</tr>
-</table>
-
-</form>
-
-<tal:block tal:condition="context/id" tal:replace="structure context/history" />
-
-</div>
-
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/file.index.html b/templates/classic/html/file.index.html
deleted file mode 100644 (file)
index 9717920..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<!-- dollarId: file.index,v 1.4 2002/01/23 05:10:27 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- >List of files - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
-  i18n:translate="">List of files</span>
-<td class="content" metal:fill-slot="content">
-
-<table class="otherinfo" tal:define="batch request/batch">
- <tr><th style="padding-right: 10" i18n:translate="">Download</th>
-     <th style="padding-right: 10" i18n:translate="">Content Type</th>
-     <th style="padding-right: 10" i18n:translate="">Uploaded By</th>
-     <th style="padding-right: 10" i18n:translate="">Date</th>
- </tr>
- <tr tal:repeat="file batch" tal:attributes="class python:['normal', 'alt'][repeat['file'].index%6/3]">
-  <td>
-   <a tal:attributes="href string:file${file/id}/${file/name}"
-      tal:content="file/name">dld link</a>
-  </td>
-  <td tal:content="file/type">content type</td>
-  <td tal:content="file/creator">creator's name</td>
-  <td tal:content="file/creation">creation date</td>
- </tr>
-
- <metal:block use-macro="templates/issue.index/macros/batch-footer" />
-
-</table>
-
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/file.item.html b/templates/classic/html/file.item.html
deleted file mode 100644 (file)
index d223fd7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">File display - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">File display</span>
-
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<form method="POST" onSubmit="return submit_once()"
-      enctype="multipart/form-data" tal:condition="context/is_view_ok"
-      tal:attributes="action context/designator">
-
-<table class="form">
- <tr>
-  <th i18n:translate="">Name</th>
-  <td tal:content="structure context/name/field"></td>
- </tr>
- <tr>
-  <th i18n:translate="">Content Type</th>
-  <td tal:content="structure context/type/field"></td>
- </tr>
-
- <tr>
-  <td>
-   &nbsp;
-   <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>
-</table>
-</form>
-
-<a tal:condition="python:context.id and context.is_view_ok()"
- tal:attributes="href string:file${context/id}/${context/name}"
- i18n:translate="">download</a>
-
-<tal:block tal:condition="context/id" tal:replace="structure context/history" />
-
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/help.html b/templates/classic/html/help.html
deleted file mode 100644 (file)
index 1571a6f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<!--
-Macros for framed help windows
--->
-
-<!-- legend for helper search results -->
-<thead>
-<tr metal:define-macro="legend">
-  <th><b>x</b></th>
-  <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
-</tr>
-</thead>
-
-<table width="100%"
-  metal:define-macro="batch_navi"
-  tal:define="prev batch/previous;
-  next batch/next;
-  "
-  tal:condition="python:prev or next">
-  <tr class="navigation">
-   <th width="30%">
-    <a tal:condition="prev"
-       tal:attributes="href python:request.indexargs_url(request.classname, {'@template':'help-list', 'property': request.form['property'].value, 'properties': request.form['properties'].value, 'form': request.form['form'].value, '@startwith':prev.first, '@pagesize':prev.size})"
-       i18n:translate="" >&lt;&lt; previous</a>
-    &nbsp;
-   </th>
-   <th i18n:translate="" width="40%"><span tal:replace="batch/start" i18n:name="start"
-    />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
-    /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
-    />
-   </th>
-   <th width="30%">
-    <a tal:condition="next"
-       tal:attributes="href python:request.indexargs_url(request.classname, {'@template':'help-list', 'property': request.form['property'].value, 'properties': request.form['properties'].value, 'form': request.form['form'].value, '@startwith':next.first, '@pagesize':next.size})"
-       i18n:translate="" >next &gt;&gt;</a>
-    &nbsp;
-   </th>
-  </tr>
- </table>
diff --git a/templates/classic/html/help_controls.js b/templates/classic/html/help_controls.js
deleted file mode 100644 (file)
index 480170a..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-// initial values for either Nosy, Superseder, Keyword and Waiting On,
-// depending on which has called
-original_field = form[field].value;
-
-// Some browsers (ok, IE) don't define the "undefined" variable.
-undefined = document.geez_IE_is_really_friggin_annoying;
-
-function trim(value) {
-  var temp = value;
-  var obj = /^(\s*)([\W\w]*)(\b\s*$)/;
-  if (obj.test(temp)) { temp = temp.replace(obj, '$2'); }
-  var obj = /  /g;
-  while (temp.match(obj)) { temp = temp.replace(obj, " "); }
-  return temp;
-}
-
-function determineList() {
-     // generate a comma-separated list of the checked items
-     var list = new String('');
-
-     // either a checkbox object or an array of checkboxes
-     var check = document.frm_help.check;
-
-     if ((check.length == undefined) && (check.checked != undefined)) {
-         // only one checkbox on page
-         if (check.checked) {
-             list = check.value;
-         }
-     } else {
-         // array of checkboxes
-         for (box=0; box < check.length; box++) {
-             if (check[box].checked) {
-                 if (list.length == 0) {
-                     separator = '';
-                 }
-                 else {
-                     separator = ',';
-                 }
-                 // we used to use an Array and push / join, but IE5.0 sux
-                 list = list + separator + check[box].value;
-             }
-         }
-     }
-     return list;
-}
-
-/**
- * update the field in the opening window;
- * the text_field variable must be set in the calling page
- */
-function updateOpener() {
-  // write back to opener window
-  if (document.frm_help.check==undefined) { return; }
-  form[field].value = text_field.value;
-}
-
-function updateList() {
-  // write back to opener window
-  if (document.frm_help.check==undefined) { return; }
-  form[field].value = determineList();
-}
-
-function updatePreview() {
-  // update the preview box
-  if (document.frm_help.check==undefined) { return; }
-  writePreview(determineList());
-}
-
-function clearList() {
-  // uncheck all checkboxes
-  if (document.frm_help.check==undefined) { return; }
-  for (box=0; box < document.frm_help.check.length; box++) {
-      document.frm_help.check[box].checked = false;
-  }
-}
-
-function reviseList_framed(form, textfield) {
-  // update the checkboxes based on the preview field
-  // alert('reviseList_framed')
-  // alert(form)
-  if (form.check==undefined)
-      return;
-  // alert(textfield)
-  var to_check;
-  var list = textfield.value.split(",");
-  if (form.check.length==undefined) {
-      check = form.check;
-      to_check = false;
-      for (val in list) {
-          if (check.value==trim(list[val])) {
-              to_check = true;
-              break;
-          }
-      }
-      check.checked = to_check;
-  } else {
-    for (box=0; box < form.check.length; box++) {
-      check = form.check[box];
-      to_check = false;
-      for (val in list) {
-          if (check.value==trim(list[val])) {
-              to_check = true;
-              break;
-          }
-      }
-      check.checked = to_check;
-    }
-  }
-}
-
-function reviseList(vals) {
-  // update the checkboxes based on the preview field
-  if (document.frm_help.check==undefined) { return; }
-  var to_check;
-  var list = vals.split(",");
-  if (document.frm_help.check.length==undefined) {
-      check = document.frm_help.check;
-      to_check = false;
-      for (val in list) {
-          if (check.value==trim(list[val])) {
-              to_check = true;
-              break;
-          }
-      }
-      check.checked = to_check;
-  } else {
-    for (box=0; box < document.frm_help.check.length; box++) {
-      check = document.frm_help.check[box];
-      to_check = false;
-      for (val in list) {
-          if (check.value==trim(list[val])) {
-              to_check = true;
-              break;
-          }
-      }
-      check.checked = to_check;
-    }
-  }
-}
-
-function resetList() {
-  // reset preview and check boxes to initial values
-  if (document.frm_help.check==undefined) { return; }
-  writePreview(original_field);
-  reviseList(original_field);
-}
-
-function writePreview(val) {
-   // writes a value to the text_preview
-   document.frm_help.text_preview.value = val;
-}
-
-function focusField(name) {
-    for(i=0; i < document.forms.length; ++i) {
-      var obj = document.forms[i].elements[name];
-      if (obj && obj.focus) {obj.focus();}
-    }
-}
-
-function selectField(name) {
-    for(i=0; i < document.forms.length; ++i) {
-      var obj = document.forms[i].elements[name];
-      if (obj && obj.focus){obj.focus();}
-      if (obj && obj.select){obj.select();}
-    }
-}
-
-function checkRequiredFields(fields)
-{
-    var bonk='';
-    var res='';
-    var argv = checkRequiredFields.arguments;
-    var argc = argv.length;
-    var input = '';
-    var val='';
-
-    for (var i=0; i < argc; i++) {
-        fi = argv[i];
-        input = document.getElementById(fi);
-        if (input) {
-            val = input.value
-            if (val == '' || val == '-1' || val == -1) {
-                if (res == '') {
-                    res = fi;
-                    bonk = input;
-                } else {
-                    res += ', '+fi;
-                }
-            }
-        } else {
-            alert('Field with id='+fi+' not found!')
-        }
-    }
-    if (res == '') {
-        return submit_once();
-    } else {
-        alert('Missing value here ('+res+')!');
-        if (window.event && window.event.returnvalue) {
-            event.returnValue = 0;    // work-around for IE
-        }
-        bonk.focus();
-        return false;
-    }
-}
-
-/**
- * seeks the given value (2nd argument)
- * in the value of the given input element (1st argument),
- * which is considered a list of values, separated by commas
- */
-function has_value(input, val)
-{
-    var actval = input.value
-    var arr = feld.value.split(',');
-    var max = arr.length;
-    for (i=0;i<max;i++) {
-        if (trim(arr[i]) == val) {
-            return true
-        }
-    }
-    return false
-}
-
-/**
- * Switch Value:
- * change the value of the given input field (might be of type text or hidden),
- * adding or removing the value of the given checkbox field (might be a radio
- * button as well)
- *
- * This function doesn't care whether or not the checkboxes of all values of
- * interest are present; but of course it doesn't have total control of the
- * text field.
- */
-function switch_val(text, check)
-{
-    var switched_val = check.value
-    var arr = text.value.split(',')
-    var max = arr.length
-    if (check.checked) {
-        for (i=0; i<max; i++) {
-            if (trim(arr[i]) == switched_val) {
-                return
-            }
-        }
-       if (text.value)
-            text.value = text.value+','+switched_val
-       else
-            text.value = switched_val
-    } else {
-        var neu = ''
-       var changed = false
-        for (i=0; i<max; i++) {
-            if (trim(arr[i]) == switched_val) {
-                changed=true
-            } else {
-                neu = neu+','+trim(arr[i])
-            }
-        }
-        if (changed) {
-            text.value = neu.substr(1)
-        }
-    }
-}
-
-/**
- * append the given value (2nd argument) to an input field
- * (1st argument) which contains comma-separated values;
- * see --> remove_val()
- *
- * This will work nicely even for batched lists
- */
-function append_val(name, val)
-{
-    var feld = document.itemSynopsis[name];
-    var actval = feld.value;
-    if (actval == '') {
-        feld.value = val
-    } else {
-        var arr = feld.value.split(',');
-        var max = arr.length;
-        for (i=0;i<max;i++) {
-            if (trim(arr[i]) == val) {
-                return
-            }
-        }
-        feld.value = actval+','+val
-    }
-}
-
-/**
- * remove the given value (2nd argument) from the comma-separated values
- * of the given input element (1st argument); see --> append_val()
- */
-function remove_val(name, val)
-{
-    var feld = document.itemSynopsis[name];
-    var actval = feld.value;
-    var changed=false;
-    if (actval == '') {
-       return
-    } else {
-        var arr = feld.value.split(',');
-        var max = arr.length;
-        var neu = ''
-        for (i=0;i<max;i++) {
-            if (trim(arr[i]) == val) {
-                changed=true
-            } else {
-                neu = neu+','+trim(arr[i])
-            }
-        }
-        if (changed) {
-            feld.value = neu.substr(1)
-        }
-    }
-}
-
-/**
- * give the focus to the element given by id
- */
-function focus2id(name)
-{
-    document.getElementById(name).focus();
-}
diff --git a/templates/classic/html/home.classlist.html b/templates/classic/html/home.classlist.html
deleted file mode 100644 (file)
index 930306b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">List of classes - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">List of classes</span>
-<td class="content" metal:fill-slot="content">
-<table class="classlist">
-
-<tal:block tal:repeat="cl db/classes">
- <tr>
-  <th class="header" colspan="2" align="left">
-   <a tal:attributes="href string:${cl/classname}"
-      tal:content="python:cl.classname.capitalize()">classname</a>
-  </th>
- </tr>
- <tr tal:repeat="prop cl/properties">
-  <th tal:content="prop/_name">name</th>
-  <td tal:content="prop/_prop">type</td>
- </tr>
-</tal:block>
-
-</table>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/home.html b/templates/classic/html/home.html
deleted file mode 100644 (file)
index 90d926a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<!--
- This is the default body that is displayed when people visit the
- tracker. The tag below lists the currently open issues. You may
- replace it with a greeting message, or a different list of issues or
- whatever. It's a good idea to have the issues on the front page though
--->
-<span tal:replace="structure python:db.issue.renderWith('index',
-    sort=[('-', 'activity')], group=[('+', 'priority')], filter=['status'],
-    columns=['id','activity','title','creator','assignedto', 'status'],
-    filterspec={'status':['-1','1','2','3','4','5','6','7']})" />
diff --git a/templates/classic/html/issue.index.html b/templates/classic/html/issue.index.html
deleted file mode 100644 (file)
index 581624c..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-<!-- $Id: issue.index.html,v 1.29 2007-09-18 17:44:26 jpend Exp $ -->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" >
-  <span tal:omit-tag="true" i18n:translate="" >List of issues</span>
-  <span tal:condition="request/dispname"
-   tal:replace="python:' - %s '%request.dispname"
-  /> - <span tal:replace="config/TRACKER_NAME" />
-</title>
-<span metal:fill-slot="body_title" tal:omit-tag="true">
-  <span tal:omit-tag="true" i18n:translate="" >List of issues</span>
-  <span tal:condition="request/dispname"
-   tal:replace="python:' - %s' % request.dispname" />
-</span>
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<tal:block tal:define="batch request/batch" tal:condition="context/is_view_ok">
- <table class="list">
-  <tr>
-   <th tal:condition="request/show/priority" i18n:translate="">Priority</th>
-   <th tal:condition="request/show/id" i18n:translate="">ID</th>
-   <th tal:condition="request/show/creation" i18n:translate="">Creation</th>
-   <th tal:condition="request/show/activity" i18n:translate="">Activity</th>
-   <th tal:condition="request/show/actor" i18n:translate="">Actor</th>
-   <th tal:condition="request/show/keyword" i18n:translate="">Keyword</th>
-   <th tal:condition="request/show/title" i18n:translate="">Title</th>
-   <th tal:condition="request/show/status" i18n:translate="">Status</th>
-   <th tal:condition="request/show/creator" i18n:translate="">Creator</th>
-   <th tal:condition="request/show/assignedto" i18n:translate="">Assigned&nbsp;To</th>
-  </tr>
- <tal:block tal:repeat="i batch" condition=true>
-  <tr tal:define="group python:[r[1] for r in request.group]"
-      tal:condition="python:group and batch.propchanged(*group)">
-   <th tal:attributes="colspan python:len(request.columns)" class="group">
-    <tal:block tal:repeat="g group">
-     <tal:block i18n:translate="" tal:content="python:str(i[g]) or '(no %s set)'%g"/>
-    </tal:block>
-   </th>
-  </tr>
-
-  <tr>
-   <td tal:condition="request/show/priority"
-       tal:content="python:i.priority.plain() or default">&nbsp;</td>
-   <td tal:condition="request/show/id" tal:content="i/id">&nbsp;</td>
-   <td class="date" tal:condition="request/show/creation"
-       tal:content="i/creation/reldate">&nbsp;</td>
-   <td class="date" tal:condition="request/show/activity"
-       tal:content="i/activity/reldate">&nbsp;</td>
-   <td class="date" tal:condition="request/show/actor"
-       tal:content="python:i.actor.plain() or default">&nbsp;</td>
-   <td tal:condition="request/show/keyword"
-       tal:content="python:i.keyword.plain() or default">&nbsp;</td>
-   <td tal:condition="request/show/title">
-    <a tal:attributes="href string:issue${i/id}"
-               tal:content="python:str(i.title.plain(hyperlink=0)) or '[no title]'">title</a>
-   </td>
-   <td tal:condition="request/show/status"
-       i18n:translate=""
-       tal:content="python:i.status.plain() or default">&nbsp;</td>
-   <td tal:condition="request/show/creator"
-       tal:content="python:i.creator.plain() or default">&nbsp;</td>
-   <td tal:condition="request/show/assignedto"
-       tal:content="python:i.assignedto.plain() or default">&nbsp;</td>
-  </tr>
-
- </tal:block>
-
- <metal:index define-macro="batch-footer">
- <tr tal:condition="batch">
-  <th tal:attributes="colspan python:len(request.columns)">
-   <table width="100%">
-    <tr class="navigation">
-     <th>
-      <a tal:define="prev batch/previous" tal:condition="prev"
-         tal:attributes="href python:request.indexargs_url(request.classname,
-         {'@startwith':prev.first, '@pagesize':prev.size})"
-         i18n:translate="">&lt;&lt; previous</a>
-      &nbsp;
-     </th>
-     <th i18n:translate=""><span tal:replace="batch/start" i18n:name="start"
-     />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
-     /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
-     /></th>
-     <th>
-      <a tal:define="next batch/next" tal:condition="next"
-         tal:attributes="href python:request.indexargs_url(request.classname,
-         {'@startwith':next.first, '@pagesize':next.size})"
-         i18n:translate="">next &gt;&gt;</a>
-      &nbsp;
-     </th>
-    </tr>
-   </table>
-  </th>
- </tr>
- </metal:index>
-</table>
-
-<a tal:attributes="href python:request.indexargs_url('issue',
-            {'@action':'export_csv'})" i18n:translate="">Download as CSV</a>
-
-<form method="GET" class="index-controls"
-    tal:attributes="action request/classname">
-
- <table class="form" tal:define="n_sort python:2">
-  <tal:block tal:repeat="n python:range(n_sort)" tal:condition="batch">
-  <tr tal:define="key python:len(request.sort)>n and request.sort[n]">
-   <th>
-    <tal:block tal:condition="not:n" i18n:translate="">Sort on:</tal:block>
-   </th>
-   <td>
-    <select tal:attributes="name python:'@sort%d'%n">
-     <option value="" i18n:translate="">- nothing -</option>
-     <option tal:repeat="col context/properties"
-             tal:attributes="value col/_name;
-                             selected python:key and col._name == key[1]"
-             tal:content="col/_name"
-             i18n:translate="">column</option>
-    </select>
-   </td>
-   <th i18n:translate="">Descending:</th>
-   <td><input type="checkbox" tal:attributes="name python:'@sortdir%d'%n;
-              checked python:key and key[0] == '-'">
-   </td>
-  </tr>
-  </tal:block>
-  <tal:block tal:repeat="n python:range(n_sort)" tal:condition="batch">
-  <tr tal:define="key python:len(request.group)>n and request.group[n]">
-   <th>
-    <tal:block tal:condition="not:n" i18n:translate="">Group on:</tal:block>
-   </th>
-   <td>
-    <select tal:attributes="name python:'@group%d'%n">
-     <option value="" i18n:translate="">- nothing -</option>
-     <option tal:repeat="col context/properties"
-             tal:attributes="value col/_name;
-                             selected python:key and col._name == key[1]"
-             tal:content="col/_name"
-             i18n:translate="">column</option>
-    </select>
-   </td>
-   <th i18n:translate="">Descending:</th>
-   <td><input type="checkbox" tal:attributes="name python:'@groupdir%d'%n;
-              checked python:key and key[0] == '-'">
-   </td>
-  </tr>
-  </tal:block>
-  <tr><td colspan="4">
-              <input type="submit" value="Redisplay" i18n:attributes="value">
-              <tal:block tal:replace="structure
-                python:request.indexargs_form(sort=0, group=0)" />
-  </td></tr>
- </table>
-</form>
-
-</tal:block>
-
-</td>
-</tal:block><tal:comment condition=false> vim: sw=1 ts=8 et si
-</tal:comment>
diff --git a/templates/classic/html/issue.item.html b/templates/classic/html/issue.item.html
deleted file mode 100644 (file)
index 41ee073..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-<!-- dollarId: issue.item,v 1.4 2001/08/03 01:19:43 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">
-<tal:block condition="context/id" i18n:translate=""
- >Issue <tal:x tal:content="context/id" i18n:name="id"
- />: <tal:x content="context/title" i18n:name="title"
- /> - <tal:x content="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:block>
-<tal:block condition="not:context/id" i18n:translate=""
- >New Issue - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:block>
-</title>
-<tal:block metal:fill-slot="body_title">
- <span tal:condition="python: not (context.id or context.is_edit_ok())"
-  tal:omit-tag="python:1" i18n:translate="">New Issue</span>
- <span tal:condition="python: not context.id and context.is_edit_ok()"
-  tal:omit-tag="python:1" i18n:translate="">New Issue Editing</span>
- <span tal:condition="python: context.id and not context.is_edit_ok()"
-  tal:omit-tag="python:1" i18n:translate="">Issue<tal:x
-  replace="context/id" i18n:name="id" /></span>
- <span tal:condition="python: context.id and context.is_edit_ok()"
-  tal:omit-tag="python:1" i18n:translate="">Issue<tal:x
-  replace="context/id" i18n:name="id" /> Editing</span>
-</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<div tal:condition="context/is_view_ok">
-
-<form method="POST" name="itemSynopsis"
-      onSubmit="return submit_once()" enctype="multipart/form-data"
-      tal:attributes="action context/designator">
-
-<table class="form">
-<tr>
- <th class="required" i18n:translate="">Title</th>
- <td colspan=3 tal:content="structure python:context.title.field(size=60)">title</td>
-</tr>
-
-<tr>
- <th class="required" i18n:translate="">Priority</th>
- <td tal:content="structure context/priority/menu">priority</td>
- <th i18n:translate="">Status</th>
- <td tal:content="structure context/status/menu">status</td>
-</tr>
-
-<tr>
- <th i18n:translate="">Superseder</th>
- <td>
-  <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
-  <span tal:condition="context/is_edit_ok" tal:replace="structure python:db.issue.classhelp('id,title', property='superseder')" />
-  <span tal:condition="context/superseder">
-   <br><span i18n:translate="">View:</span>
-     <a tal:repeat="sup context/superseder"
-        tal:content="python:sup['id'] + ', '*(not repeat['sup'].end)"
-        tal:attributes="href string:issue${sup/id}"></a>
-  </span>
- </td>
- <th i18n:translate="">Nosy List</th>
- <td>
-  <span tal:replace="structure context/nosy/field" />
-  <span tal:condition="context/is_edit_ok" tal:replace="structure
-python:db.user.classhelp('username,realname,address', property='nosy', width='600')" /><br>
- </td>
-</tr>
-
-<tr>
- <th i18n:translate="">Assigned To</th>
- <td tal:content="structure context/assignedto/menu">assignedto menu</td>
- <th i18n:translate="">Keywords</th>
- <td>
-  <span tal:replace="structure context/keyword/field" />
-  <span tal:condition="context/is_edit_ok" tal:replace="structure python:db.keyword.classhelp(property='keyword')" />
- </td>
-</tr>
-
-<tr tal:condition="context/is_edit_ok">
- <th i18n:translate="">Change Note</th>
- <td colspan=3>
-  <textarea tal:content="request/form/@note/value | default"
-            name="@note" wrap="hard" rows="5" cols="80"></textarea>
- </td>
-</tr>
-
-<tr tal:condition="context/is_edit_ok">
- <th i18n:translate="">File</th>
- <td colspan=3><input type="file" name="@file" size="40"></td>
-</tr>
-
-<tr tal:condition="context/is_edit_ok">
- <td>
-  &nbsp;
-  <input type="hidden" name="@template" value="item">
-  <input type="hidden" name="@required" value="title,priority">
- </td>
- <td colspan=3>
-  <span tal:replace="structure context/submit">submit button</span>
-  <a tal:condition="context/id" tal:attributes="href context/copy_url"
-   i18n:translate="">Make a copy</a>
- </td>
-</tr>
-
-</table>
-</form>
-
-<tal:block tal:condition="not:context/id" i18n:translate="">
-<table class="form">
-<tr>
- <td>Note:&nbsp;</td>
- <th class="required">highlighted</th>
- <td>&nbsp;fields are required.</td>
-</tr>
-</table>
-</tal:block>
-
-<p tal:condition="context/id" i18n:translate="">
- Created on <b tal:content="context/creation" i18n:name="creation" />
- by <b tal:content="context/creator" i18n:name="creator" />,
- last changed <b content="context/activity" i18n:name="activity" />
- by <b tal:content="context/actor" i18n:name="actor" />.
-</p>
-
-<table class="files" tal:condition="context/files">
- <tr><th colspan="5" class="header" i18n:translate="">Files</th></tr>
- <tr>
-  <th i18n:translate="">File name</th>
-  <th i18n:translate="">Uploaded</th>
-  <th i18n:translate="">Type</th>
-  <th i18n:translate="">Edit</th>
-  <th i18n:translate="">Remove</th>
- </tr>
- <tr tal:repeat="file context/files">
-  <td>
-   <a tal:attributes="href file/download_url"
-      tal:content="file/name">dld link</a>
-  </td>
-  <td>
-   <span tal:content="file/creator">creator's name</span>,
-   <span tal:content="file/creation">creation date</span>
-  </td>
-  <td tal:content="file/type" />
-  <td><a tal:condition="file/is_edit_ok"
-          tal:attributes="href string:file${file/id}">edit</a>
-  </td>
-  <td>
-   <form style="padding:0" tal:condition="context/is_edit_ok"
-         tal:attributes="action string:issue${context/id}">
-    <input type="hidden" name="@remove@files" tal:attributes="value file/id">
-    <input type="hidden" name="@action" value="edit">
-    <input type="submit" value="remove" i18n:attributes="value">
-   </form>
-  </td>
- </tr>
-</table>
-
-<table class="messages" tal:condition="context/messages">
- <tr><th colspan="4" class="header" i18n:translate="">Messages</th></tr>
- <tal:block tal:repeat="msg context/messages/reverse">
-  <tr>
-   <th><a tal:attributes="href string:msg${msg/id}"
-    i18n:translate="">msg<tal:x replace="msg/id" i18n:name="id" /> (view)</a></th>
-   <th i18n:translate="">Author: <tal:x replace="msg/author"
-       i18n:name="author" /></th>
-   <th i18n:translate="">Date: <tal:x replace="msg/date"
-       i18n:name="date" /></th>
-   <th>
-    <form style="padding:0" tal:condition="context/is_edit_ok"
-          tal:attributes="action string:issue${context/id}">
-     <input type="hidden" name="@remove@messages" tal:attributes="value msg/id">
-     <input type="hidden" name="@action" value="edit">
-     <input type="submit" value="remove" i18n:attributes="value">
-    </form>
-   </th>
-  </tr>
-  <tr>
-   <td colspan="4" class="content">
-    <pre tal:content="structure msg/content/hyperlinked">content</pre>
-   </td>
-  </tr>
- </tal:block>
-</table>
-
-<tal:block tal:condition="context/id" tal:replace="structure context/history" />
-
-</div>
-
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/issue.search.html b/templates/classic/html/issue.search.html
deleted file mode 100644 (file)
index cff5122..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">Issue searching - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Issue searching</span>
-<td class="content" metal:fill-slot="content">
-
-<form method="GET" name="itemSynopsis"
-      tal:attributes="action request/classname">
-      
-<table class="form" tal:define="
-   cols python:request.columns or 'id activity title status assignedto'.split();
-   sort_on python:request.sort and request.sort[0] or nothing;
-   sort_desc python:sort_on and sort_on[0] == '-';
-   sort_on python:(sort_on and sort_on[1]) or 'activity';
-   group_on python:request.group and request.group[0] or nothing;
-   group_desc python:group_on and group_on[0] == '-';
-   group_on python:(group_on and group_on[1]) or 'priority';
-
-   search_input templates/page/macros/search_input;
-   search_date templates/page/macros/search_date;
-   column_input templates/page/macros/column_input;
-   sort_input templates/page/macros/sort_input;
-   group_input templates/page/macros/group_input;
-   search_select templates/page/macros/search_select;
-   search_select_translated templates/page/macros/search_select_translated;
-   search_multiselect templates/page/macros/search_multiselect;">
-
-<tr>
- <th class="header">&nbsp;</th>
- <th class="header" i18n:translate="">Filter on</th>
- <th class="header" i18n:translate="">Display</th>
- <th class="header" i18n:translate="">Sort on</th>
- <th class="header" i18n:translate="">Group on</th>
-</tr>
-
-<tr tal:define="name string:@search_text">
-  <th i18n:translate="">All text*:</th>
-  <td metal:use-macro="search_input"></td>
-  <td>&nbsp;</td>
-  <td>&nbsp;</td>
-  <td>&nbsp;</td>
-</tr>
-
-<tr tal:define="name string:title">
-  <th i18n:translate="">Title:</th>
-  <td metal:use-macro="search_input"></td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td>&nbsp;</td>
-</tr>
-
-<tr tal:define="name string:keyword;
-                db_klass string:keyword;
-                db_content string:name;">
-  <th i18n:translate="">Keyword:</th>
-  <td metal:use-macro="search_select">
-    <option metal:fill-slot="extra_options" value="-1" i18n:translate=""
-            tal:attributes="selected python:value == '-1'">not selected</option>
-  </td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td metal:use-macro="group_input"></td>
-</tr>
-
-<tr tal:define="name string:id">
-  <th i18n:translate="">ID:</th>
-  <td metal:use-macro="search_input"></td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td>&nbsp;</td>
-</tr>
-
-<tr tal:define="name string:creation">
-  <th i18n:translate="">Creation Date:</th>
-  <td metal:use-macro="search_date"></td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td metal:use-macro="group_input"></td>
-</tr>
-
-<tr tal:define="name string:creator;
-                db_klass string:user;
-                db_content string:username;"
-    tal:condition="db/user/is_view_ok">
-  <th i18n:translate="">Creator:</th>
-  <td metal:use-macro="search_select">
-    <option metal:fill-slot="extra_options" i18n:translate=""
-            tal:attributes="value request/user/id">created by me</option>
-  </td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td metal:use-macro="group_input"></td>
-</tr>
-
-<tr tal:define="name string:activity">
-  <th i18n:translate="">Activity:</th>
-  <td metal:use-macro="search_date"></td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td>&nbsp;</td>
-</tr>
-
-<tr tal:define="name string:actor;
-                db_klass string:user;
-                db_content string:username;"
-    tal:condition="db/user/is_view_ok">
-  <th i18n:translate="">Actor:</th>
-  <td metal:use-macro="search_select">
-    <option metal:fill-slot="extra_options" i18n:translate=""
-            tal:attributes="value request/user/id">done by me</option>
-  </td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td>&nbsp;</td>
-</tr>
-
-<tr tal:define="name string:priority;
-                db_klass string:priority;
-                db_content string:name;">
-  <th i18n:translate="">Priority:</th>
-  <td metal:use-macro="search_select_translated">
-    <option metal:fill-slot="extra_options" value="-1" i18n:translate=""
-            tal:attributes="selected python:value == '-1'">not selected</option>
-  </td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td metal:use-macro="group_input"></td>
-</tr>
-
-<tr tal:define="name string:status;
-                db_klass string:status;
-                db_content string:name;">
-  <th i18n:translate="">Status:</th>
-  <td metal:use-macro="search_select_translated">
-    <tal:block metal:fill-slot="extra_options">
-      <option value="-1,1,2,3,4,5,6,7" i18n:translate=""
-              tal:attributes="selected python:value == '-1,1,2,3,4,5,6,7'">not resolved</option>
-      <option value="-1" i18n:translate=""
-              tal:attributes="selected python:value == '-1'">not selected</option>
-    </tal:block>
-  </td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td metal:use-macro="group_input"></td>
-</tr>
-
-<tr tal:define="name string:assignedto;
-                db_klass string:user;
-                db_content string:username;"
-    tal:condition="db/user/is_view_ok">
-  <th i18n:translate="">Assigned to:</th>
-  <td metal:use-macro="search_select">
-    <tal:block metal:fill-slot="extra_options">
-      <option tal:attributes="value request/user/id"
-       i18n:translate="">assigned to me</option>
-      <option value="-1" tal:attributes="selected python:value == '-1'"
-       i18n:translate="">unassigned</option>
-    </tal:block>
-  </td>
-  <td metal:use-macro="column_input"></td>
-  <td metal:use-macro="sort_input"></td>
-  <td metal:use-macro="group_input"></td>
-</tr>
-
-<tr>
- <th i18n:translate="">No Sort or group:</th>
- <td>&nbsp;</td>
- <td>&nbsp;</td>
- <td><input type="radio" name="@sort" value=""></td>
- <td><input type="radio" name="@group" value=""></td>
-</tr>
-
-<tr>
-<th i18n:translate="">Pagesize:</th>
-<td><input name="@pagesize" size="3" value="50"
-           tal:attributes="value request/form/@pagesize/value | default"></td>
-</tr>
-
-<tr>
-<th i18n:translate="">Start With:</th>
-<td><input name="@startwith" size="3" value="0"
-           tal:attributes="value request/form/@startwith/value | default"></td>
-</tr>
-
-<tr>
-<th i18n:translate="">Sort Descending:</th>
-<td><input type="checkbox" name="@sortdir"
-           tal:attributes="checked sort_desc">
-</td>
-</tr>
-
-<tr>
-<th i18n:translate="">Group Descending:</th>
-<td><input type="checkbox" name="@groupdir"
-           tal:attributes="checked group_desc">
-</td>
-</tr>
-
-<tr tal:condition="python:request.user.hasPermission('Edit', 'query')">
- <th i18n:translate="">Query name**:</th>
- <td tal:define="value request/form/@queryname/value | nothing">
-  <input name="@queryname" tal:attributes="value value">
-  <input type="hidden" name="@old-queryname" tal:attributes="value value">
- </td>
-</tr>
-
-<tr>
-  <td>
-   &nbsp;
-   <input type="hidden" name="@action" value="search">
-  </td>
-  <td><input type="submit" value="Search" i18n:attributes="value"></td>
-</tr>
-
-<tr><td>&nbsp;</td>
- <td colspan="4" class="help">
-  <span i18n:translate="" tal:omit-tag="true">
-   *: The "all text" field will look in message bodies and issue titles
-  </span><br>
-  <span tal:condition="python:request.user.hasPermission('Edit', 'query')"
-   i18n:translate="" tal:omit-tag="true"
-  >
-   **: If you supply a name, the query will be saved off and available as a
-       link in the sidebar
-  </span>
- </td>
-</tr>
-</table>
-
-</form>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/keyword.item.html b/templates/classic/html/keyword.item.html
deleted file mode 100644 (file)
index cf1e26a..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<!-- dollarId: keyword.item,v 1.3 2002/05/22 00:32:34 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">Keyword editing - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Keyword editing</span>
-<td class="content" metal:fill-slot="content">
-
-<table class="otherinfo" tal:define="keywords db/keyword/list"
-       tal:condition="keywords">
- <tr><th colspan="4" class="header" i18n:translate="">Existing Keywords</th></tr>
- <tr tal:repeat="start python:range(0, len(keywords), 4)">
-  <td width="25%" tal:define="batch python:utils.Batch(keywords, 4, start)"
-      tal:repeat="keyword batch">
-    <a tal:attributes="href string:keyword${keyword/id}"
-       tal:content="keyword/name">keyword here</a>
-  </td>
- </tr>
- <tr>
-  <td colspan="4" style="border-top: 1px solid gray" i18n:translate="">
-   To edit an existing keyword (for spelling or typing errors),
-   click on its entry above.
-  </td>
- </tr>
-</table>
-
-<p class="help" tal:condition="not:context/id" i18n:translate="">
- To create a new keyword, enter it below and click "Submit New Entry".
-</p>
-
-<form method="POST" onSubmit="return submit_once()"
-      enctype="multipart/form-data"
-      tal:attributes="action context/designator">
-
- <table class="form">
-  <tr>
-   <th i18n:translate="">Keyword</th>
-   <td tal:content="structure context/name/field">name</td>
-  </tr>
-
-  <tr>
-   <td>
-    &nbsp;
-    <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
-   </td>
-  </tr>
- </table>
-</form>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/msg.index.html b/templates/classic/html/msg.index.html
deleted file mode 100644 (file)
index 02405dc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- >List of messages - <span tal:replace="config/TRACKER_NAME"
- i18n:name="tracker"/></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Message listing</span>
-<td class="content" metal:fill-slot="content">
-<table tal:define="batch request/batch" class="messages">
- <tr><th colspan=2 class="header" i18n:translate="">Messages</th></tr>
- <tal:block tal:repeat="msg batch">
-  <tr>
-   <th tal:content="string:Author: ${msg/author}">author</th>
-   <th tal:content="string:Date: ${msg/date}">date</th>
-  </tr>
-  <tr>
-   <td colspan="2"><pre tal:content="msg/content">content</pre></td>
-  </tr>
- </tal:block>
-
- <metal:block use-macro="templates/issue.index/macros/batch-footer" />
-
-</table>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/msg.item.html b/templates/classic/html/msg.item.html
deleted file mode 100644 (file)
index e755174..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<!-- dollarId: msg.item,v 1.3 2002/05/22 00:32:34 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">
-<tal:block condition="context/id" i18n:translate=""
- >Message <span tal:replace="context/id" i18n:name="id"
- /> - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:block>
-<tal:block condition="not:context/id" i18n:translate=""
- >New Message - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:block>
-</title>
-<tal:block metal:fill-slot="body_title">
- <span tal:condition="python: not (context.id or context.is_edit_ok())"
-  tal:omit-tag="python:1" i18n:translate="">New Message</span>
- <span tal:condition="python: not context.id and context.is_edit_ok()"
-  tal:omit-tag="python:1" i18n:translate="">New Message Editing</span>
- <span tal:condition="python: context.id and not context.is_edit_ok()"
-  tal:omit-tag="python:1" i18n:translate="">Message<tal:x
-  replace="context/id" i18n:name="id" /></span>
- <span tal:condition="python: context.id and context.is_edit_ok()"
-  tal:omit-tag="python:1" i18n:translate="">Message<tal:x
-  replace="context/id" i18n:name="id" /> Editing</span>
-</tal:block>
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<div tal:condition="context/is_view_ok">
-<table class="form">
-
-<tr>
- <th i18n:translate="">Author</th>
- <td tal:content="context/author"></td>
-</tr>
-
-<tr>
- <th i18n:translate="">Recipients</th>
- <td tal:content="context/recipients"></td>
-</tr>
-
-<tr>
- <th i18n:translate="">Date</th>
- <td tal:content="context/date"></td>
-</tr>
-</table>
-
-<table class="messages">
- <tr><th colspan=2 class="header" i18n:translate="">Content</th></tr>
- <tr>
-  <td class="content" colspan=2><pre tal:content="structure context/content/hyperlinked"></pre></td>
- </tr>
-</table>
-
-<table class="files" tal:condition="context/files">
- <tr><th colspan="2" class="header" i18n:translate="">Files</th></tr>
- <tr>
-  <th i18n:translate="">File name</th>
-  <th i18n:translate="">Uploaded</th>
- </tr>
- <tr tal:repeat="file context/files">
-  <td>
-   <a tal:attributes="href string:file${file/id}/${file/name}"
-      tal:content="file/name">dld link</a>
-  </td>
-  <td>
-   <span tal:content="file/creator">creator's name</span>,
-   <span tal:content="file/creation">creation date</span>
-  </td>
- </tr>
-</table>
-
-<tal:block tal:replace="structure context/history" />
-
-</div>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/page.html b/templates/classic/html/page.html
deleted file mode 100644 (file)
index cd64875..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-<!-- vim:sw=2 sts=2
---><tal:block metal:define-macro="icing"
-><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title metal:define-slot="head_title">title goes here</title>
-<link rel="stylesheet" type="text/css" href="@@file/style.css">
-<meta http-equiv="Content-Type"
- tal:attributes="content string:text/html;; charset=${request/client/charset}" />
-<script tal:replace="structure request/base_javascript">
-</script>
-<metal:x define-slot="more-javascript" />
-
-</head>
-<body class="body">
-
-<table class="body"
- tal:define="
-kw_edit python:request.user.hasPermission('Edit', 'keyword');
-kw_create python:request.user.hasPermission('Create', 'keyword');
-kw_edit_link python:kw_edit and db.keyword.list();
-columns string:id,activity,title,creator,status;
-columns_showall string:id,activity,title,creator,assignedto,status;
-status_notresolved string:-1,1,2,3,4,5,6,7;
-"
->
-
-<tr>
- <td class="page-header-left">&nbsp;</td>
- <td class="page-header-top">
-   <div id="body-title">
-     <h2><span metal:define-slot="body_title">body title</span></h2>
-   </div>
-   <div id="searchbox">
-     <form method="GET" action="issue">
-       <input type="hidden" name="@columns"
-             tal:attributes="value columns_showall"
-             value="id,activity,title,creator,assignedto,status"/>
-       <input type="hidden" name="@sort" value="activity"/>
-       <input type="hidden" name="@group" value="priority"/>
-       <input id="search-text" name="@search_text" size="10"
-              tal:attributes="value request/search_text | default" />
-       <input type="submit" id="submit" name="submit" value="Search"
-              i18n:attributes="value" />
-     </form>
-  </div>
- </td>
-</tr>
-
-<tr>
- <td rowspan="2" valign="top" class="sidebar">
-  <p class="classblock"
-     tal:condition="python:request.user.hasPermission('View', 'query')">
-   <span i18n:translate=""
-    ><b>Your Queries</b> (<a href="query?@template=edit">edit</a>)</span><br>
-   <tal:block tal:repeat="qs request/user/queries">
-    <a href="#" tal:attributes="href string:${qs/klass}?${qs/url}&@dispname=${qs/name}"
-       tal:content="qs/name">link</a><br>
-   </tal:block>
-  </p>
-
-  <form method="POST" tal:attributes="action request/base">
-   <p class="classblock"
-       tal:condition="python:request.user.hasPermission('View', 'issue')">
-    <b i18n:translate="">Issues</b><br>
-    <span tal:condition="python:request.user.hasPermission('Create', 'issue')">
-      <a href="issue?@template=item" i18n:translate="">Create New</a><br>
-    </span>
-    <a href="#"
-       tal:attributes="href python:request.indexargs_url('issue', {
-      '@sort': '-activity',
-      '@group': 'priority',
-      '@filter': 'status,assignedto',
-      '@columns': columns,
-      '@search_text': '',
-      'status': status_notresolved,
-      'assignedto': '-1',
-      '@dispname': i18n.gettext('Show Unassigned'),
-     })"
-       i18n:translate="">Show Unassigned</a><br>
-    <a href="#"
-       tal:attributes="href python:request.indexargs_url('issue', {
-      '@sort': '-activity',
-      '@group': 'priority',
-      '@filter': 'status',
-      '@columns': columns_showall,
-      '@search_text': '',
-      'status': status_notresolved,
-      '@dispname': i18n.gettext('Show All'),
-     })"
-       i18n:translate="">Show All</a><br>
-    <a href="issue?@template=search" i18n:translate="">Search</a><br>
-    <input type="submit" class="form-small" value="Show issue:"
-     i18n:attributes="value"><input class="form-small" size="4"
-     type="text" name="@number">
-    <input type="hidden" name="@type" value="issue">
-    <input type="hidden" name="@action" value="show">
-   </p>
-  </form>
-
-  <p class="classblock"
-     tal:condition="python:kw_edit or kw_create">
-   <b i18n:translate="">Keywords</b><br>
-   <span tal:condition="python:request.user.hasPermission('Create', 'keyword')">
-    <a href="keyword?@template=item" i18n:translate="">Create New</a><br>
-   </span>
-   <span tal:condition="kw_edit_link">
-    <a href="keyword?@template=item" i18n:translate="">Edit Existing</a><br>
-   </span>
-  </p>
-
-  <p class="classblock"
-       tal:condition="python:request.user.hasPermission('View', 'user')">
-   <b i18n:translate="">Administration</b><br>
-   <span tal:condition="python:request.user.hasPermission('Edit', None)">
-    <a href="home?@template=classlist" i18n:translate="">Class List</a><br>
-   </span>
-   <span tal:condition="python:request.user.hasPermission('View', 'user')
-                            or request.user.hasPermission('Edit', 'user')">
-    <a href="user"  i18n:translate="">User List</a><br>
-   </span>
-   <a tal:condition="python:request.user.hasPermission('Create', 'user')"
-      href="user?@template=item" i18n:translate="">Add User</a>
-  </p>
-
-  <form method="POST" tal:condition="python:request.user.username=='anonymous'"
-        tal:attributes="action request/base">
-   <p class="userblock">
-    <b i18n:translate="">Login</b><br>
-    <input size="10" name="__login_name"><br>
-    <input size="10" type="password" name="__login_password"><br>
-    <input type="hidden" name="@action" value="Login">
-    <input type="checkbox" name="remember" id="remember">
-    <label for="remember" i18n:translate="">Remember me?</label><br>
-    <input type="submit" value="Login" i18n:attributes="value"><br>
-    <input type="hidden" name="__came_from" tal:attributes="value string:${request/base}${request/env/PATH_INFO}">
-    <span tal:replace="structure request/indexargs_form" />
-    <a href="user?@template=register"
-       tal:condition="python:request.user.hasPermission('Create', 'user')"
-     i18n:translate="">Register</a><br>
-    <a href="user?@template=forgotten" i18n:translate="">Lost&nbsp;your&nbsp;login?</a><br>
-   </p>
-  </form>
-
-  <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
-   <b i18n:translate="">Hello, <span i18n:name="user"
-    tal:replace="python:request.user.username.plain(escape=1)">username</span></b><br>
-    <a href="#"
-       tal:attributes="href python:request.indexargs_url('issue', {
-      '@sort': '-activity',
-      '@group': 'priority',
-      '@filter': 'status,assignedto',
-      '@columns': 'id,activity,title,creator,status',
-      '@search_text': '',
-      'status': status_notresolved,
-      'assignedto': request.user.id,
-      '@dispname': i18n.gettext('Your Issues'),
-     })"
-    i18n:translate="">Your Issues</a><br>
-   <a href="#" tal:attributes="href string:user${request/user/id}"
-    i18n:translate="">Your Details</a><br>
-   <a href="#" tal:attributes="href python:request.indexargs_url('',
-       {'@action':'logout'})" i18n:translate="">Logout</a>
-  </p>
-  <p class="userblock">
-   <b i18n:translate="">Help</b><br>
-   <a href="http://roundup.sourceforge.net/doc-1.0/"
-    i18n:translate="">Roundup docs</a>
-  </p>
- </td>
- <td>
-  <p tal:condition="options/error_message | nothing" class="error-message"
-     tal:repeat="m options/error_message" tal:content="structure m" />
-  <p tal:condition="options/ok_message | nothing" class="ok-message">
-    <span tal:repeat="m options/ok_message"
-       tal:content="structure string:$m <br/ > " />
-     <a class="form-small" tal:attributes="href request/current_url"
-        i18n:translate="">clear this message</a>
-  </p>
- </td>
-</tr>
-<tr>
- <td class="content" metal:define-slot="content">Page content goes here</td>
-</tr>
-
-</table>
-
-<pre tal:condition="request/form/debug | nothing" tal:content="request">
-</pre>
-
-</body>
-</html>
-</tal:block>
-
-<!--
-The following macros are intended to be used in search pages.
-
-The invoking context must define a "name" variable which names the
-property being searched.
-
-See issue.search.html in the classic template for examples.
--->
-
-<!-- creates a th and a label: -->
-<th metal:define-macro="th_label"
-    tal:define="required required | python:[]"
-    tal:attributes="class python:(name in required) and 'required' or nothing">
-  <label tal:attributes="for name" tal:content="label" i18n:translate="">text</label>
-       <metal:x define-slot="behind_the_label" />
-</th>
-
-<td metal:define-macro="search_input">
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-</td>
-
-<td metal:define-macro="search_date">
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-  <a class="classhelp"
-        tal:attributes="href python:'''javascript:help_window('issue?@template=calendar&property=%s&form=itemSynopsis', 300, 200)'''%name">(cal)</a>
-</td>
-
-<td metal:define-macro="search_popup">
-  <!--
-    context needs to specify the popup "columns" as a comma-separated
-    string (eg. "id,title" or "id,name,description") as well as name
-  -->
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-  <span tal:replace="structure python:db.issue.classhelp(columns,
-                                      property=name)" />
-</td>
-
-<td metal:define-macro="search_select">
-  <select tal:attributes="name name; id name"
-          tal:define="value python:request.form.getvalue(name)">
-    <option value="" i18n:translate="">don't care</option>
-    <metal:slot define-slot="extra_options" />
-    <option value="" i18n:translate="" disabled="disabled">------------</option>
-    <option tal:repeat="s python:db[db_klass].list()"
-            tal:attributes="value s/id; selected python:value == s.id"
-            tal:content="python:s[db_content]"></option>
-  </select>
-</td>
-
-<!-- like search_select, but translates the further values.
-Could extend it (METAL 1.1 attribute "extend-macro")
--->
-<td metal:define-macro="search_select_translated">
-  <select tal:attributes="name name; id name"
-          tal:define="value python:request.form.getvalue(name)">
-    <option value="" i18n:translate="">don't care</option>
-    <metal:slot define-slot="extra_options" />
-    <option value="" i18n:translate="" disabled="disabled">------------</option>
-    <option tal:repeat="s python:db[db_klass].list()"
-            tal:attributes="value s/id; selected python:value == s.id"
-                                               tal:content="python:s[db_content]"
-                                               i18n:translate=""></option>
-  </select>
-</td>
-
-<!-- currently, there is no convenient API to get a list of all roles -->
-<td metal:define-macro="search_select_roles"
-         tal:define="onchange onchange | nothing">
-  <select name=roles id=roles tal:attributes="onchange onchange">
-    <option value="" i18n:translate="">don't care</option>
-    <option value="" i18n:translate="" disabled="disabled">------------</option>
-    <option value="User">User</option>
-    <option value="Admin">Admin</option>
-    <option value="Anonymous">Anonymous</option>
-  </select>
-</td>
-
-<td metal:define-macro="search_multiselect">
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-  <span tal:replace="structure python:db[db_klass].classhelp(db_content,
-                                        property=name, width='600')" />
-</td>
-
-<td metal:define-macro="search_checkboxes">
- <ul class="search-checkboxes"
-     tal:define="value python:request.form.getvalue(name);
-                 values python:value and value.split(',') or []">
- <li tal:repeat="s python:db[db_klass].list()">
-  <input type="checkbox" tal:attributes="name name; id string:$name-${s/id};
-    value s/id; checked python:s.id in values" />
-  <label tal:attributes="for string:$name-${s/id}"
-         tal:content="python:s[db_content]" />
- </li>
- <li metal:define-slot="no_value_item">
-  <input type="checkbox" value="-1" tal:attributes="name name;
-     id string:$name--1; checked python:value == '-1'" />
-  <label tal:attributes="for string:$name--1" i18n:translate="">no value</label>
- </li>
- </ul>
-</td>
-
-<td metal:define-macro="column_input">
-  <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"
-         tal:attributes="value name;
-                         checked python:name == sort_on">
-</td>
-
-<td metal:define-macro="group_input">
-  <input type="radio" name="@group"
-         tal:attributes="value name;
-                         checked python:name == group_on">
-</td>
-
-<!--
-The following macros are intended for user editing.
-
-The invoking context must define a "name" variable which names the
-property being searched; the "edit_ok" variable tells whether the
-current user is allowed to edit.
-
-See user.item.html in the classic template for examples.
--->
-<script metal:define-macro="user_utils" type="text/javascript" src="@@file/user_utils.js"></script>
-
-<!-- src: value will be re-used for other input fields -->
-<input metal:define-macro="user_src_input"
-    type="text" tal:attributes="onblur python:edit_ok and 'split_name(this)';
-    id name; name name; value value; readonly not:edit_ok"
-    value="heinz.kunz">
-<!-- normal: no re-using -->
-<input metal:define-macro="user_normal_input" type="text"
-    tal:attributes="id name; name name; value value; readonly not:edit_ok"
-    value="heinz">
-<!-- password: type; no initial value -->
-    <input metal:define-macro="user_pw_input" type="password"
-    tal:attributes="id name; name name; readonly not:edit_ok" value="">
-    <input metal:define-macro="user_confirm_input" type="password"
-    tal:attributes="id name; name string:@confirm@$name; readonly not:edit_ok" value="">
-
diff --git a/templates/classic/html/query.edit.html b/templates/classic/html/query.edit.html
deleted file mode 100644 (file)
index 2c586f1..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- >"Your Queries" Editing - <span tal:replace="config/TRACKER_NAME"
- i18n:name="tracker" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">"Your Queries" Editing</span>
-
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="not:context/is_edit_ok"
- i18n:translate="">You are not allowed to edit queries.</span>
-
-<script language="javascript">
-// This exists solely because I can't figure how to get the & into an
-// attributes TALES expression, and so it keeps getting quoted.
-function retire(qid) {
-    window.location = 'query'+qid+'?@action=retire&@template=edit';
-}
-</script>
-
-<form method="POST" onSubmit="return submit_once()" action="query"
-      enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<table class="list" width="100%"
-       tal:define="uid request/user/id; mine request/user/queries">
-
-<tr><th i18n:translate="">Query</th>
-    <th i18n:translate="">Include in "Your Queries"</th>
-    <th i18n:translate="">Edit</th>
-    <th i18n:translate="">Private to you?</th>
-    <th>&nbsp;</th>
-</tr>
-
-<tr tal:repeat="query mine">
- <tal:block condition="query/is_retired">
-
- <td><a tal:attributes="href string:${query/klass}?${query/url}"
-        tal:content="query/name">query</a></td>
-
- <td metal:define-macro="include">
-  <select tal:condition="python:query.id not in mine"
-          tal:attributes="name string:user${uid}@add@queries">
-    <option value="" i18n:translate="">leave out</option>
-    <option tal:attributes="value query/id" i18n:translate="">include</option>
-  </select>
-  <select tal:condition="python:query.id in mine"
-          tal:attributes="name string:user${uid}@remove@queries">
-    <option value="" i18n:translate="">leave in</option>
-    <option tal:attributes="value query/id" i18n:translate="">remove</option>
-  </select>
- </td>
-
- <td colspan="3" i18n:translate="">[query is retired]</td>
-
- <!-- <td> maybe offer "restore" some day </td> -->
- </tal:block>
-</tr>
-
-<tr tal:repeat="query mine">
- <tal:block condition="not:query/is_retired">
- <td><a tal:attributes="href string:${query/klass}?${query/url}"
-        tal:content="query/name">query</a></td>
-
- <td metal:use-macro="template/macros/include" />
-
- <td><a tal:attributes="href string:query${query/id}" i18n:translate="">edit</a></td>
-
- <td>
-  <select tal:attributes="name string:query${query/id}@private_for">
-   <option tal:attributes="selected python:query.private_for == uid;
-           value uid" i18n:translate="">yes</option>
-   <option tal:attributes="selected python:query.private_for == None"
-           value="-1" i18n:translate="">no</option>
-  </select>
- </td>
-
- <td>
-  <input type="button" value="Delete" i18n:attributes="value"
-  tal:attributes="onClick python:'''retire('%s')'''%query.id">
-  </td>
-  </tal:block>
-</tr>
-
-<tr tal:define="queries python:db.query.filter(filterspec={'private_for':None})"
-     tal:repeat="query queries">
- <tal:block condition="python: query.creator != uid">
- <td><a tal:attributes="href string:${query/klass}?${query/url}"
-        tal:content="query/name">query</a></td>
-
- <td metal:use-macro="template/macros/include" />
-
- <td colspan="3" tal:condition="query/is_edit_ok">
-  <a tal:attributes="href string:query${query/id}" i18n:translate="">edit</a>
- </td>
- <td tal:condition="not:query/is_edit_ok" colspan="3"
-    i18n:translate="">[not yours to edit]</td>
- </tal:block>
-</tr>
-
-<tr><td colspan="5">
-   <input type="hidden" name="@action" value="edit">
-   <input type="hidden" name="@template" value="edit">
-   <input type="submit" value="Save Selection" i18n:attributes="value">
-</td></tr>
-
-</table>
-
-</form>
-</td>
-</tal:block>
diff --git a/templates/classic/html/query.item.html b/templates/classic/html/query.item.html
deleted file mode 100644 (file)
index 453e13d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<!-- query.item -->
-<span tal:replace="structure context/renderQueryForm" />
-
diff --git a/templates/classic/html/style.css b/templates/classic/html/style.css
deleted file mode 100644 (file)
index 72e7ffc..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/* main page styles */
-body.body {
-  font-family: sans-serif, Arial, Helvetica;
-  background-color: white;
-  color: #333;
-  margin: 0;
-}
-a[href]:hover {
-  color:blue;
-  text-decoration: underline;
-}
-a[href], a[href]:link {
-  color:blue;
-  text-decoration: none;
-}
-
-table.body {
-  border: 0;
-  padding: 0;
-  border-spacing: 0;
-  border-collapse: separate;
-}
-
-td.page-header-left {
-  padding: 5px;
-  border-bottom: 1px solid #444;
-}
-td.sidebar {
-  padding: 1px 0 0 1px;
-  white-space: nowrap;
-}
-
-/* don't display the sidebar when printing */
-@media print {
-    td.page-header-left {
-        display: none;
-    }
-    td.sidebar {
-        display: none;
-    }
-    .index-controls {
-        display: none;
-    }
-    #searchbox {
-        display: none;
-    }
-}
-
-td.page-header-top {
-  padding: 5px;
-  border-bottom: 1px solid #444;
-}
-#searchbox {
-    float: right;
-}
-
-div#body-title {
-  float: left;
-}
-
-
-div#searchbox {
-  float: right;
-  padding-top: 1em;
-}
-
-div#searchbox input#search-text {
-  width: 10em;
-}
-
-form {
-  margin: 0;
-}
-
-textarea {
-    font-family: monospace;
-}
-
-td.sidebar p.classblock {
-  padding: 2px 5px 2px 5px;
-  margin: 1px;
-  border: 1px solid #444;
-  background-color: #eee;
-}
-
-td.sidebar p.userblock {
-  padding: 2px 5px 2px 5px;
-  margin: 1px 1px 1px 1px;
-  border: 1px solid #444;
-  background-color: #eef;
-}
-
-.form-small {
-  padding: 0;
-  font-size: 75%;
-}
-
-
-td.content {
-  padding: 1px 5px 1px 5px;
-  vertical-align: top;
-  width: 100%;
-}
-
-td.date, th.date { 
-  white-space: nowrap;
-}
-
-p.ok-message {
-  background-color: #22bb22;
-  padding: 5px;
-  color: white;
-  font-weight: bold;
-}
-p.error-message {
-  background-color: #bb2222;
-  padding: 5px;
-  color: white;
-  font-weight: bold;
-}
-p.error-message a[href] {
-  color: white;
-  text-decoration: underline;
-}
-
-
-/* style for search forms */
-ul.search-checkboxes {
-    display: inline;
-    padding: 0;
-    list-style: none;
-}
-ul.search-checkboxes > li {
-    display: inline;
-    padding-right: .5em;
-}
-
-
-/* style for forms */
-table.form {
-  padding: 2px;
-  border-spacing: 0;
-  border-collapse: separate;
-}
-
-table.form th {
-  color: #338;
-  text-align: right;
-  vertical-align: top;
-  font-weight: normal;
-  white-space: nowrap;
-}
-
-table.form th.header {
-  font-weight: bold;
-  background-color: #eef;
-  text-align: left;
-}
-
-table.form th.required {
-  font-weight: bold;
-}
-
-table.form td {
-  color: #333;
-  empty-cells: show;
-  vertical-align: top;
-}
-
-table.form td.optional {
-  font-weight: bold;
-  font-style: italic;
-}
-
-table.form td.html {
-  color: #777;
-}
-
-/* style for lists */
-table.list {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.list th {
-  padding: 0 4px 0 4px;
-  color: #404070;
-  background-color: #eef;
-  border: 1px solid white;
-  vertical-align: top;
-  empty-cells: show;
-}
-table.list th a[href]:hover { color: #404070 }
-table.list th a[href]:link { color: #404070 }
-table.list th a[href] { color: #404070 }
-table.list th.group {
-  background-color: #f4f4ff;
-  text-align: center;
-}
-
-table.list td {
-  padding: 0 4px 0 4px;
-  border: 1px solid white;
-  color: #404070;
-  background-color: #efefef;
-  vertical-align: top;
-  empty-cells: show;
-}
-
-table.list tr.navigation th {
-  width: 33%;
-  border-style: hidden;
-  text-align: center;
-}
-table.list tr.navigation td {
-    border: none
-}
-table.list tr.navigation th:first-child {
-  text-align: left;
-}
-table.list tr.navigation th:last-child {
-  text-align: right;
-}
-
-
-/* style for message displays */
-table.messages {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.messages th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.messages th {
-  font-weight: bold;
-  color: black;
-  text-align: left;
-  border-bottom: 1px solid #afafaf;
-}
-
-table.messages td {
-  font-family: monospace;
-  background-color: #efefef;
-  border-bottom: 1px solid #afafaf;
-  color: black;
-  empty-cells: show;
-  border-right: 1px solid #afafaf;
-  vertical-align: top;
-  padding: 2px 5px 2px 5px;
-}
-
-table.messages td:first-child {
-  border-left: 1px solid #afafaf;
-  border-right: 1px solid #afafaf;
-}
-
-/* style for file displays */
-table.files {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.files th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.files th {
-  border-bottom: 1px solid #afafaf;
-  font-weight: bold;
-  text-align: left;
-}
-
-table.files td {
-  font-family: monospace;
-  empty-cells: show;
-}
-
-/* style for history displays */
-table.history {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.history th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-  font-size: 100%;
-}
-
-table.history th {
-  border-bottom: 1px solid #afafaf;
-  font-weight: bold;
-  text-align: left;
-  font-size: 90%;
-}
-
-table.history td {
-  font-size: 90%;
-  vertical-align: top;
-  empty-cells: show;
-}
-
-
-/* style for class list */
-table.classlist {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.classlist th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.classlist th {
-  font-weight: bold;
-  text-align: left;
-}
-
-
-/* style for class help display */
-table.classhelp {      /* the table-layout: fixed;        */ 
-  table-layout: fixed; /* compromises quality for speed   */
-  overflow: hidden;
-  font-size: .9em;
-  padding-bottom: 3em;
-}
-
-table.classhelp th {
-  font-weight: normal;
-  text-align: left;
-  color: #444;
-  background-color: #efefef;
-  border-bottom: 1px solid #afafaf;
-  border-top: 1px solid #afafaf;
-  text-transform: uppercase;
-  vertical-align: middle;
-  line-height:1.5em;
-}
-
-table.classhelp td {
-  vertical-align: middle;
-  padding-right: .2em;
-  border-bottom: 1px solid #efefef;
-  text-align: left;
-  empty-cells: show;
-  white-space: nowrap;
-  vertical-align: middle;
-}
-
-table.classhelp tr:hover {
-  background-color: #eee;
-}
-
-label.classhelp-label {
-  cursor: pointer;
-}
-
-#classhelp-controls {
-  position: fixed;
-  display: block;
-  top: auto;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  padding: .5em;
-  border-top: 2px solid #444;
-  background-color: #eee;
-}
-
-#classhelp-controls input.apply {
-  width: 7em;
-  font-weight: bold;
-  margin-right: 2em;
-  margin-left: 2em;
-}
-
-#classhelp-controls input.preview {
-   margin-right: 3em;
-   margin-left: 1em;
-}
-
-/* style for "other" displays */
-table.otherinfo {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.otherinfo th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.otherinfo th {
-  border-bottom: 1px solid #afafaf;
-  font-weight: bold;
-  text-align: left;
-}
-input[type="text"]:focus,
-input[type="checkbox"]:focus,
-input[type="radio"]:focus,
-input[type="password"]:focus,
-textarea:focus, select:focus {
-  background-color: #ffffc0;
-}
-
-/* vim: sts=2 sw=2 et
-*/
diff --git a/templates/classic/html/user.forgotten.html b/templates/classic/html/user.forgotten.html
deleted file mode 100644 (file)
index 3f0a472..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">Password reset request - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Password reset request</span>
-<td class="content" metal:fill-slot="content">
-
-<p i18n:translate="">You have two options if you have forgotten your password.
-If you know the email address you registered with, enter it below.</p>
-
-<form method="POST" onSubmit="return submit_once()"
-      tal:attributes="action context/designator">
-    <table class="form">
-      <tr>
-        <th i18n:translate="">Email Address:</th>
-        <td><input name="address"></td>
-      </tr>
-      <tr>
-        <td>&nbsp;</td>
-        <td>
-          <input type="hidden" name="@action" value="passrst">
-          <input type="hidden" name="@template" value="forgotten">
-          <input type="submit" value="Request password reset"
-           i18n:attributes="value">
-        </td>
-      </tr>
-</table>
-
-<p i18n:translate="">Or, if you know your username, then enter it below.</p>
-
-<table class="form">
- <tr><th i18n:translate="">Username:</th> <td><input name="username"></td> </tr>
- <tr><td></td><td><input type="submit" value="Request password reset"
-   i18n:attributes="value"></td></tr>
-</table>
-</form>
-
-<p i18n:translate="">A confirmation email will be sent to you -
-please follow the instructions within it to complete the reset process.</p>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/user.help-search.html b/templates/classic/html/user.help-search.html
deleted file mode 100644 (file)
index 8436897..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<html
-  tal:define="form request/form/form/value;
-  field request/form/property/value"
-  >
-  <head>
-    <title>Search input for user helper</title>
-    <script language="Javascript" type="text/javascript"
-        tal:content="structure string:<!--
-        // this is the name of the field in the original form that we're working on
-        form  = parent.opener.document.${form};
-        field  = '${field}';
-        //-->">
-    </script>
-    <script type="text/javascript" src="@@file/help_controls.js"></script>
-    <link rel="stylesheet" type="text/css" href="@@file/style.css" />
-  </head>
-  <body onload="parent.submit.url='...'"
-    tal:define="
-qs request/env/QUERY_STRING;
-qs python:'&'.join([a for a in qs.split('&') if not a.startswith('@template=')])"
->
-    <pre tal:content="request/env/QUERY_STRING" tal:condition=false />
-    <form method="GET" name="itemSynopsis"
-      target="list"
-      tal:attributes="action request/classname"
-      tal:define="
-      property request/form/property/value;
-   cols python:request.columns or 'id username address realname roles'.split();
-   sort_on request/sort | nothing;
-   sort_desc python:sort_on and request.sort[0][0] == '-';
-   sort_on python:sort_on and request.sort[0][1] or 'lastname';
-
-   search_input templates/page/macros/search_input;
-   search_select templates/page/macros/search_select;
-   search_select_roles templates/page/macros/search_select_roles;
-   required python:[];
-   th_label templates/page/macros/th_label;
-   ">
-   <input type="hidden" name="@template" value="help-list">
-   <input type="hidden" name="property" value="" tal:attributes="value property">
-   <input type="hidden" name="form" value="" tal:attributes="value request/form/form/value">
-   <table>
-<tr tal:define="name string:username; label string:Username:">
-  <th metal:use-macro="th_label">Name</th>
-  <td metal:use-macro="search_input"><input type=text></td>
-</tr>
-
-<tr tal:define="name string:phone; label string:Phone number">
-  <th metal:use-macro="th_label">Phone</th>
-  <td metal:use-macro="search_input"><input type=text></td>
-</tr>
-
-<tr tal:define="name string:roles;
-                onchange string:this.form.submit();
-                label string:Roles:"
-                >
-  <th metal:use-macro="th_label">role</th>
-  <td metal:use-macro="search_select_roles">
-    <select>
-      <option value="">jokester</option>
-    </select>
-  </td>
-</tr>
-
-<tr>
-  <td>&nbsp;</td>
-  <td>
-    <input type="hidden" name="@action" value="search">
-    <input type="submit" value="Search" i18n:attributes="value">
-    <input type="reset">
-    <input type="hidden" value="username,realname,phone,organisation,roles" name="properties">
-    <input type="text" name="@pagesize" id="sp-pagesize" value="25" size="2">
-    <label for="sp-pagesize" i18n:translate="">Pagesize</label>
-  </td>
-</tr>
-
-   </table>
-
-</form>
-<pre tal:content="request" tal:condition=false />
-<script type="text/javascript"><!--
-  focus2id('username');
-//--></script>
-  </body>
-</html>
diff --git a/templates/classic/html/user.help.html b/templates/classic/html/user.help.html
deleted file mode 100644 (file)
index b338c2b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html tal:define="property request/form/property/value;
-qs request/env/QUERY_STRING;
-qs python:'&'.join([a for a in qs.split('&') if not a.startswith('@template=')]);
-form request/form/form/value;
-field request/form/property/value">
-  <head>
-      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
-      <meta http-equiv="Content-Type"
-       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
-      <tal:block tal:condition="python:request.form.has_key('property')">
-      <title><tal:x i18n:translate=""><tal:x i18n:name="property"
-       tal:content="property" i18n:translate="" /> help - <span i18n:name="tracker"
-              tal:replace="config/TRACKER_NAME" /></tal:x></title>
-      <script language="Javascript" type="text/javascript"
-             tal:condition=false
-          tal:content="structure string:<!--
-          // this is the name of the field in the original form that we're working on
-          form  = window.opener.document.${form};
-          field  = '${field}';
-          //-->">
-      </script>
-      <script src="@@file/help_controls.js"
-     tal:condition=false type="text/javascript"><!--
-      //--></script>
-      </tal:block>
-  </head>
-<frameset rows="123,*,62">
-  <frame src="#" tal:attributes="src string:?@template=help-search&${qs}" name="search">
-  <!-- for search results: help-list -->
-  <frame
-  tal:attributes="src string:?@template=help-empty&${qs}"
-  name="list">
-  <frame
-  tal:attributes="src string:?@template=help-submit&${qs}"
-  name="submit">
-  <!-- -->
-</frameset>
-<noframes>
-  <body>
-<p i18n:translate="">
-Your browser is not capable of using frames; you should be redirected immediately,
-or visit <a href="#" tal:attributes="href string:?${qs}&template=help-noframes"
-i18n:name="link">this link</a>.
-</p>
-</body>
-</noframes>
-
-</html>
diff --git a/templates/classic/html/user.index.html b/templates/classic/html/user.index.html
deleted file mode 100644 (file)
index 021e2b8..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<!-- dollarId: user.index,v 1.3 2002/07/09 05:29:51 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">User listing - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">User listing</span>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))"
- i18n:translate="">You are not allowed to view this page.</span>
-
-<span tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')"
- i18n:translate="">Please login with your username and password.</span>
-
-<table width="100%" tal:condition="context/is_view_ok" class="list">
-<tr>
- <th i18n:translate="">Username</th>
- <th i18n:translate="">Real name</th>
- <th i18n:translate="">Organisation</th>
- <th i18n:translate="">Email address</th>
- <th i18n:translate="">Phone number</th>
- <th tal:condition="context/is_edit_ok" i18n:translate="">Retire</th>
-</tr>
-<tal:block repeat="user context/list">
-<tr tal:attributes="class python:['normal', 'alt'][repeat['user'].index%6/3]">
- <td>
-  <a tal:attributes="href string:user${user/id}"
-     tal:content="user/username">username</a>
- </td>
- <td tal:content="python:user.realname.plain() or default">&nbsp;</td>
- <td tal:content="python:user.organisation.plain() or default">&nbsp;</td>
- <td tal:content="python:user.address.email() or default">&nbsp;</td>
- <td tal:content="python:user.phone.plain() or default">&nbsp;</td>
- <td tal:condition="context/is_edit_ok">
-  <a tal:attributes="href string:user${user/id}?@action=retire&@template=index"
-   i18n:translate="">retire</a>
- </td>
-</tr>
-</tal:block>
-</table>
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/user.item.html b/templates/classic/html/user.item.html
deleted file mode 100644 (file)
index bafccd2..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:doc metal:use-macro="templates/page/macros/icing"
-define="edit_ok context/is_edit_ok"
->
-<title metal:fill-slot="head_title">
-<tal:if condition="context/id" i18n:translate=""
- >User <tal:x content="context/id" i18n:name="id"
- />: <tal:x content="context/username" i18n:name="title"
- /> - <tal:x content="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:if>
-<tal:if condition="not:context/id" i18n:translate=""
- >New User - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:if>
-</title>
-<metal:slot fill-slot="more-javascript">
-<script metal:use-macro="templates/page/macros/user_utils"></script>
-<script type="text/javascript" src="@@file/help_controls.js"></script>
-</metal:slot>
-<tal:block metal:fill-slot="body_title"
-  define="edit_ok context/is_edit_ok">
- <span tal:condition="python: not (context.id or edit_ok)"
-  tal:omit-tag="python:1" i18n:translate="">New User</span>
- <span tal:condition="python: not context.id and edit_ok"
-  tal:omit-tag="python:1" i18n:translate="">New User Editing</span>
- <span tal:condition="python: context.id and not edit_ok"
-  tal:omit-tag="python:1" i18n:translate="">User<tal:x
-  replace="context/id" i18n:name="id" /></span>
- <span tal:condition="python: context.id and edit_ok"
-  tal:omit-tag="python:1" i18n:translate="">User<tal:x
-  replace="context/id" i18n:name="id" /> Editing</span>
-</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<div tal:condition="context/is_view_ok">
-
-<form method="POST"
-      name="itemSynopsis"
-      tal:define="required python:'username address'.split()"
-      enctype="multipart/form-data"
-      tal:attributes="action context/designator;
-      onSubmit python:'return checkRequiredFields(\'%s\')'%'\', \''.join(required);
-      ">
-<table class="form" tal:define="
-  th_label templates/page/macros/th_label;
-  src_input templates/page/macros/user_src_input;
-  normal_input templates/page/macros/user_normal_input;
-  pw_input templates/page/macros/user_pw_input;
-  confirm_input templates/page/macros/user_confirm_input;
-  edit_ok context/is_edit_ok;
-  ">
- <tr tal:define="name string:realname; label string:Name; value context/realname; edit_ok edit_ok">
-  <th metal:use-macro="th_label">Name</th>
-  <td><input name="realname" metal:use-macro="src_input"></td>
- </tr>
- <tr tal:define="name string:username; label string:Login Name; value context/username">
-   <th metal:use-macro="th_label">Login Name</th>
-   <td><input metal:use-macro="src_input"></td>
- </tr>
- <tal:if condition="edit_ok">
- <tr tal:define="name string:password; label string:Login Password">
-  <th metal:use-macro="th_label">Login Password</th>
-  <td><input metal:use-macro="pw_input" type="password"></td>
- </tr>
- <tr tal:define="name string:password; label string:Confirm Password">
-  <th metal:use-macro="th_label">Confirm Password</th>
-  <td><input metal:use-macro="confirm_input" type="password"></td>
- </tr>
- </tal:if>
- <tal:if condition="python:request.user.hasPermission('Web Roles')">
- <tr tal:define="name string:roles; label string:Roles;">
-  <th><label for="roles" i18n:translate="">Roles</label></th>
-  <td tal:define="gips context/id">
-    <tal:subif condition=gips define="value context/roles">
-      <input metal:use-macro="normal_input">
-    </tal:subif>
-    <tal:subif condition="not:gips" define="value db/config/NEW_WEB_USER_ROLES">
-      <input metal:use-macro="normal_input">
-    </tal:subif>
-   <tal:block i18n:translate="">(to give the user more than one role,
-    enter a comma,separated,list)</tal:block>
-  </td>
- </tr>
- </tal:if>
-
- <tr tal:define="name string:phone; label string:Phone; value context/phone">
-  <th metal:use-macro="th_label">Phone</th>
-  <td><input name="phone" metal:use-macro="normal_input"></td>
- </tr>
-
- <tr tal:define="name string:organisation; label string:Organisation; value context/organisation">
-  <th metal:use-macro="th_label">Organisation</th>
-  <td><input name="organisation" metal:use-macro="normal_input"></td>
- </tr>
-
- <tr tal:condition="python:edit_ok or context.timezone"
-     tal:define="name string:timezone; label string:Timezone; value context/timezone">
-  <th metal:use-macro="th_label">Timezone</th>
-  <td><input name="timezone" metal:use-macro="normal_input">
-   <tal:block tal:condition="edit_ok" i18n:translate="">(this is a numeric hour offset, the default is
-    <span tal:replace="db/config/DEFAULT_TIMEZONE" i18n:name="zone"
-    />)</tal:block>
-  </td>
- </tr>
-
- <tr tal:define="name string:address; label string:E-mail address; value context/address">
-  <th metal:use-macro="th_label">E-mail address</th>
-  <td tal:define="mailto python:context.address.field(id='address');
-         mklink python:mailto and not edit_ok">
-      <a href="mailto:calvin@the-z.org"
-                 tal:attributes="href string:mailto:$value"
-                 tal:content="value"
-          tal:condition="python:mklink">calvin@the-z.org</a>
-      <tal:if condition=edit_ok>
-      <input metal:use-macro="src_input" value="calvin@the-z.org">
-      </tal:if>
-      &nbsp;
-  </td>
- </tr>
-
- <tr>
-  <th><label for="alternate_addresses" i18n:translate="">Alternate E-mail addresses<br>One address per line</label></th>
-  <td>
-    <textarea rows=5 cols=40 tal:replace="structure context/alternate_addresses/multiline">nobody@nowhere.org
-anybody@everywhere.net
-(alternate_addresses)
-    </textarea>
-  </td>
- </tr>
-
- <tr tal:condition="edit_ok">
-  <td>
-   &nbsp;
-   <input type="hidden" name="@template" value="item">
-   <input type="hidden" name="@required" value="username,address"
-          tal:attributes="value python:','.join(required)">
-  </td>
-  <td><input type="submit" value="save" tal:replace="structure context/submit"><!--submit button here-->
-    <input type=reset>
-  </td>
- </tr>
-</table>
-</form>
-
-<tal:block tal:condition="not:context/id" i18n:translate="">
-<table class="form">
-<tr>
- <td>Note:&nbsp;</td>
- <th class="required">highlighted</th>
- <td>&nbsp;fields are required.</td>
-</tr>
-</table>
-</tal:block>
-
-<tal:block tal:condition="context/id" tal:replace="structure context/history" />
-
-</div>
-
-</td>
-
-</tal:doc>
diff --git a/templates/classic/html/user.register.html b/templates/classic/html/user.register.html
deleted file mode 100644 (file)
index b7b1749..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title"
- i18n:translate="">Registering with <span i18n:name="tracker"
- tal:replace="db/config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Registering with <span i18n:name="tracker"
- tal:replace="db/config/TRACKER_NAME" /></span>
-<td class="content" metal:fill-slot="content">
-
-<form method="POST" onSubmit="return submit_once()"
-      enctype="multipart/form-data"
-      tal:attributes="action context/designator">
-
-<table class="form">
- <tr>
-  <th i18n:translate="">Name</th>
-  <td tal:content="structure context/realname/field">realname</td>
- </tr>
- <tr>
-  <th class="required" i18n:translate="">Login Name</th>
-  <td tal:content="structure context/username/field">username</td>
- </tr>
- <tr>
-  <th class="required" i18n:translate="">Login Password</th>
-  <td tal:content="structure context/password/field">password</td>
- </tr>
- <tr>
-  <th class="required" i18n:translate="">Confirm Password</th>
-  <td tal:content="structure context/password/confirm">password</td>
- </tr>
- <tr tal:condition="python:request.user.hasPermission('Web Roles')">
-  <th i18n:translate="">Roles</th>
-  <td tal:condition="exists:item"
-      tal:content="structure context/roles/field">roles</td>
-  <td tal:condition="not:exists:item">
-   <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">Phone</th>
-  <td tal:content="structure context/phone/field">phone</td>
- </tr>
- <tr>
-  <th i18n:translate="">Organisation</th>
-  <td tal:content="structure context/organisation/field">organisation</td>
- </tr>
- <tr>
-  <th class="required" i18n:translate="">E-mail address</th>
-  <td tal:content="structure context/address/field">address</td>
- </tr>
- <tr>
-  <th i18n:translate="">Alternate E-mail addresses<br>One address per line</th>
-  <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
- </tr>
-
- <tr>
-  <td>&nbsp;</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="submit" name="submit" value="Register" i18n:attributes="value">
-  </td>
- </tr>
-</table>
-</form>
-
-<tal:block tal:condition="not:context/id" i18n:translate="">
-<table class="form">
-<tr>
- <td>Note:&nbsp;</td>
- <th class="required">highlighted</th>
- <td>&nbsp;fields are required.</td>
-</tr>
-</table>
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/templates/classic/html/user.rego_progress.html b/templates/classic/html/user.rego_progress.html
deleted file mode 100644 (file)
index 4d6bfe4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title"
- i18n:translate="">Registration in progress - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Registration in progress...</span>
-<td class="content" metal:fill-slot="content">
-
-<p i18n:translate="">You will shortly receive an email
-to confirm your registration. To complete the registration process,
-visit the link indicated in the email.
-</p>
-
-</td>
-</tal:block>
diff --git a/templates/classic/html/user_utils.js b/templates/classic/html/user_utils.js
deleted file mode 100644 (file)
index 7b2946d..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-// User Editing Utilities
-
-/**
- * for new users:
- * Depending on the input field which calls it, takes the value
- * and dispatches it to certain other input fields:
- *
- * address
- *  +-> username
- *  |    `-> realname
- *  `-> organisation
- */
-function split_name(that) {
-    var raw = that.value
-    var val = trim(raw)
-    if (val == '') {
-        return
-    }
-    var username=''
-    var realname=''
-    var address=''
-    switch (that.name) {
-        case 'address':
-            address=val
-            break
-        case 'username':
-            username=val
-            break
-        case 'realname':
-            realname=val
-            break
-        case 'firstname':
-        case 'lastname':
-           return
-        default:
-            alert('Ooops - unknown name field '+that.name+'!')
-            return
-    }
-    var the_form = that.form;
-
-    function field_empty(name) {
-        return the_form[name].value == ''
-    }
-
-    // no break statements - on purpose!
-    switch (that.name) {
-        case 'address':
-            var split1 = address.split('@')
-            if (field_empty('username')) {
-                username = split1[0]
-                the_form.username.value = username
-            }
-            if (field_empty('organisation')) {
-                the_form.organisation.value = default_organisation(split1[1])
-            }
-        case 'username':
-            if (field_empty('realname')) {
-                realname = Cap(username.split('.').join(' '))
-                the_form.realname.value = realname
-            }
-        case 'realname':
-            if (field_empty('username')) {
-                username = Cap(realname.replace(' ', '.'))
-                the_form.username.value = username
-            }
-            if (the_form.firstname && the_form.lastname) {
-                var split2 = realname.split(' ')
-                var firstname='', lastname=''
-                firstname = split2[0]
-                lastname = split2.slice(1).join(' ')
-                if (field_empty('firstname')) {
-                    the_form.firstname.value = firstname
-                }
-                if (field_empty('lastname')) {
-                    the_form.lastname.value = lastname
-                }
-            }
-    }
-}
-
-function SubCap(str) {
-    switch (str) {
-        case 'de': case 'do': case 'da':
-        case 'du': case 'von':
-            return str;
-    }
-    if (str.toLowerCase().slice(0,2) == 'mc') {
-        return 'Mc'+str.slice(2,3).toUpperCase()+str.slice(3).toLowerCase()
-    }
-    return str.slice(0,1).toUpperCase()+str.slice(1).toLowerCase()
-}
-
-function Cap(str) {
-    var liz = str.split(' ')
-    for (var i=0; i<liz.length; i++) {
-        liz[i] = SubCap(liz[i])
-    }
-    return liz.join(' ')
-}
-
-/**
- * Takes a domain name (behind the @ part of an email address)
- * Customise this to handle the mail domains you're interested in 
- */
-function default_organisation(orga) {
-    switch (orga.toLowerCase()) {
-        case 'gmx':
-        case 'yahoo':
-            return ''
-        default:
-            return orga
-    }
-}
-
diff --git a/templates/classic/initial_data.py b/templates/classic/initial_data.py
deleted file mode 100644 (file)
index 101768b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# TRACKER INITIAL PRIORITY AND STATUS VALUES
-#
-pri = db.getclass('priority')
-pri.create(name=''"critical", order="1")
-pri.create(name=''"urgent", order="2")
-pri.create(name=''"bug", order="3")
-pri.create(name=''"feature", order="4")
-pri.create(name=''"wish", order="5")
-
-stat = db.getclass('status')
-stat.create(name=''"unread", order="1")
-stat.create(name=''"deferred", order="2")
-stat.create(name=''"chatting", order="3")
-stat.create(name=''"need-eg", order="4")
-stat.create(name=''"in-progress", order="5")
-stat.create(name=''"testing", order="6")
-stat.create(name=''"done-cbb", order="7")
-stat.create(name=''"resolved", order="8")
-
-# create the two default users
-user = db.getclass('user')
-user.create(username="admin", password=adminpw,
-    address=admin_email, roles='Admin')
-user.create(username="anonymous", roles='Anonymous')
-
-# add any additional database creation steps here - but only if you
-# haven't initialised the database with the admin "initialise" command
-
-
-# vim: set filetype=python sts=4 sw=4 et si
-#SHA: b1da2e72a7fe9f26086f243eb744135b085101d9
diff --git a/templates/classic/schema.py b/templates/classic/schema.py
deleted file mode 100644 (file)
index 85fa495..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-
-#
-# TRACKER SCHEMA
-#
-
-# Class automatically gets these properties:
-#   creation = Date()
-#   activity = Date()
-#   creator = Link('user')
-#   actor = Link('user')
-
-# Priorities
-pri = Class(db, "priority",
-                name=String(),
-                order=Number())
-pri.setkey("name")
-
-# Statuses
-stat = Class(db, "status",
-                name=String(),
-                order=Number())
-stat.setkey("name")
-
-# Keywords
-keyword = Class(db, "keyword",
-                name=String())
-keyword.setkey("name")
-
-# User-defined saved searches
-query = Class(db, "query",
-                klass=String(),
-                name=String(),
-                url=String(),
-                private_for=Link('user'))
-
-# add any additional database schema configuration here
-
-user = Class(db, "user",
-                username=String(),
-                password=Password(),
-                address=String(),
-                realname=String(),
-                phone=String(),
-                organisation=String(),
-                alternate_addresses=String(),
-                queries=Multilink('query'),
-                roles=String(),     # comma-separated string of Role names
-                timezone=String())
-user.setkey("username")
-
-# FileClass automatically gets this property in addition to the Class ones:
-#   content = String()    [saved to disk in <tracker home>/db/files/]
-#   type = String()       [MIME type of the content, default 'text/plain']
-msg = FileClass(db, "msg",
-                author=Link("user", do_journal='no'),
-                recipients=Multilink("user", do_journal='no'),
-                date=Date(),
-                summary=String(),
-                files=Multilink("file"),
-                messageid=String(),
-                inreplyto=String())
-
-file = FileClass(db, "file",
-                name=String())
-
-# IssueClass automatically gets these properties in addition to the Class ones:
-#   title = String()
-#   messages = Multilink("msg")
-#   files = Multilink("file")
-#   nosy = Multilink("user")
-#   superseder = Multilink("issue")
-issue = IssueClass(db, "issue",
-                assignedto=Link("user"),
-                keyword=Multilink("keyword"),
-                priority=Link("priority"),
-                status=Link("status"))
-
-#
-# TRACKER SECURITY SETTINGS
-#
-# See the configuration and customisation document for information
-# about security setup.
-
-#
-# REGULAR USERS
-#
-# Give the regular users access to the web and email interface
-db.security.addPermissionToRole('User', 'Web Access')
-db.security.addPermissionToRole('User', 'Email Access')
-
-# Assign the access and edit Permissions for issue, file and message
-# to regular users now
-for cl in 'issue', 'file', 'msg', 'keyword':
-    db.security.addPermissionToRole('User', 'View', cl)
-    db.security.addPermissionToRole('User', 'Edit', cl)
-    db.security.addPermissionToRole('User', 'Create', cl)
-for cl in 'priority', 'status':
-    db.security.addPermissionToRole('User', 'View', cl)
-
-# May users view other user information? Comment these lines out
-# if you don't want them to
-db.security.addPermissionToRole('User', 'View', 'user')
-
-# Users should be able to edit their own details -- this permission is
-# limited to only the situation where the Viewed or Edited item is their own.
-def own_record(db, userid, itemid):
-    '''Determine whether the userid matches the item being accessed.'''
-    return userid == itemid
-p = db.security.addPermission(name='View', klass='user', check=own_record,
-    description="User is allowed to view their own user details")
-db.security.addPermissionToRole('User', p)
-p = db.security.addPermission(name='Edit', klass='user', check=own_record,
-    description="User is allowed to edit their own user details")
-db.security.addPermissionToRole('User', p)
-
-# Users should be able to edit and view their own queries. They should also
-# be able to view any marked as not private. They should not be able to
-# edit others' queries, even if they're not private
-def view_query(db, userid, itemid):
-    private_for = db.query.get(itemid, 'private_for')
-    if not private_for: return True
-    return userid == private_for
-def edit_query(db, userid, itemid):
-    return userid == db.query.get(itemid, 'creator')
-p = db.security.addPermission(name='View', klass='query', check=view_query,
-    description="User is allowed to view their own and public queries")
-db.security.addPermissionToRole('User', p)
-p = db.security.addPermission(name='Edit', klass='query', check=edit_query,
-    description="User is allowed to edit their queries")
-db.security.addPermissionToRole('User', p)
-p = db.security.addPermission(name='Create', klass='query',
-    description="User is allowed to create queries")
-db.security.addPermissionToRole('User', p)
-
-
-#
-# ANONYMOUS USER PERMISSIONS
-#
-# Let anonymous users access the web interface. Note that almost all
-# trackers will need this Permission. The only situation where it's not
-# required is in a tracker that uses an HTTP Basic Authenticated front-end.
-db.security.addPermissionToRole('Anonymous', 'Web Access')
-
-# Let anonymous users access the email interface (note that this implies
-# that they will be registered automatically, hence they will need the
-# "Create" user Permission below)
-# This is disabled by default to stop spam from auto-registering users on
-# public trackers.
-#db.security.addPermissionToRole('Anonymous', 'Email Access')
-
-# Assign the appropriate permissions to the anonymous user's Anonymous
-# Role. Choices here are:
-# - Allow anonymous users to register
-db.security.addPermissionToRole('Anonymous', 'Create', 'user')
-
-# Allow anonymous users access to view issues (and the related, linked
-# information)
-for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status':
-    db.security.addPermissionToRole('Anonymous', 'View', cl)
-
-# [OPTIONAL]
-# Allow anonymous users access to create or edit "issue" items (and the
-# related file and message items)
-#for cl in 'issue', 'file', 'msg':
-#   db.security.addPermissionToRole('Anonymous', 'Create', cl)
-#   db.security.addPermissionToRole('Anonymous', 'Edit', cl)
-
-
-# vim: set filetype=python sts=4 sw=4 et si :
diff --git a/templates/minimal/.cvsignore b/templates/minimal/.cvsignore
deleted file mode 100644 (file)
index d90d51d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-*.pyc
-*.pyo
-htmlbase.py
-*.cover
diff --git a/templates/minimal/TEMPLATE-INFO.txt b/templates/minimal/TEMPLATE-INFO.txt
deleted file mode 100644 (file)
index 0cb35b5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-Name: minimal
-Description: This is an empty tracker - it must be customised for it to be
-             useful! It only defines the bare minimum of information - the
-             user database and the two default users (admin and anonymous).
-             The rest is entirely up to you! Not recommended for first-time
-             Roundup users (it's easier to tweak the Classic tracker).
-Intended-For: Roundup experts who need a clean slate to start with.
-
diff --git a/templates/minimal/detectors/.cvsignore b/templates/minimal/detectors/.cvsignore
deleted file mode 100644 (file)
index 4162d5e..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-*.pyc
-*.pyo
-*.cover
diff --git a/templates/minimal/detectors/userauditor.py b/templates/minimal/detectors/userauditor.py
deleted file mode 100644 (file)
index dd7fcc4..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net)
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-#   The above copyright notice and this permission notice shall be included in
-#   all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-#$Id: userauditor.py,v 1.8 2007-09-12 21:11:14 jpend Exp $
-
-import re
-
-# regular expression thanks to: http://www.regular-expressions.info/email.html
-# this is the "99.99% solution for syntax only".
-email_regexp = (r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*", r"(localhost|(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]))")
-email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
-email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
-
-def valid_address(address):
-    ''' If we see an @-symbol in the address then check against the full
-        RFC syntax. Otherwise it is a local-only address so only check
-        the local part of the RFC syntax.
-    '''
-    if '@' in address:
-        return email_rfc.match(address)
-    else:
-        return email_local.match(address)
-
-def get_addresses(user):
-    ''' iterate over all known addresses in a newvalues dict
-        this takes of the address/alterate_addresses handling
-    '''
-    if user.has_key('address'):
-        yield user['address']
-    if user.get('alternate_addresses', None):
-        for address in user['alternate_addresses'].split('\n'):
-            yield address
-
-def audit_user_fields(db, cl, nodeid, newvalues):
-    ''' Make sure user properties are valid.
-
-        - email address is syntactically valid
-        - email address is unique
-        - roles specified exist
-        - timezone is valid
-    '''
-
-    for address in get_addresses(newvalues):
-        if not valid_address(address):
-            raise ValueError, 'Email address syntax is invalid'
-
-        check_main = db.user.stringFind(address=address)
-        # make sure none of the alts are owned by anyone other than us (x!=nodeid)
-        check_alts = [x for x in db.user.filter(None, {'alternate_addresses' : address}) if x != nodeid]
-        if check_main or check_alts:
-            raise ValueError, 'Email address %s already in use' % address
-
-    for rolename in [r.lower().strip() for r in newvalues.get('roles', '').split(',')]:
-            if rolename and not db.security.role.has_key(rolename):
-                raise ValueError, 'Role "%s" does not exist'%rolename
-
-    tz = newvalues.get('timezone', None)
-    if tz:
-        # if they set a new timezone validate the timezone by attempting to
-        # use it before we store it to the db.
-        import roundup.date
-        import datetime
-        try:
-            TZ = roundup.date.get_timezone(tz)
-            dt = datetime.datetime.now()
-            local = TZ.localize(dt).utctimetuple()
-        except IOError:
-            raise ValueError, 'Timezone "%s" does not exist' % tz
-        except ValueError:
-            raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz
-
-def init(db):
-    # fire before changes are made
-    db.user.audit('set', audit_user_fields)
-    db.user.audit('create', audit_user_fields)
-
-# vim: sts=4 sw=4 et si
diff --git a/templates/minimal/extensions/README.txt b/templates/minimal/extensions/README.txt
deleted file mode 100644 (file)
index ff4dff3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-This directory is for tracker extensions:
-
-- CGI Actions
-- Templating functions
-
-See the customisation doc for more information.
diff --git a/templates/minimal/html/_generic.404.html b/templates/minimal/html/_generic.404.html
deleted file mode 100644 (file)
index 71c9e0e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
-<head>
-<title>Item Not Found</title>
-</head>
-
-<body>
-There is no <span tal:content="context/_classname" /> with id <span tal:content="context/id"/>
-</body>
-</html>
diff --git a/templates/minimal/html/_generic.calendar.html b/templates/minimal/html/_generic.calendar.html
deleted file mode 100644 (file)
index dbc3b57..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<!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" />
-  <meta http-equiv="Content-Type" content="text/html; charset=utf-8;" />
-  <title tal:content="string:Roundup Calendar"></title>
-  <script language="Javascript"
-          type="text/javascript"
-          tal:content="structure string:
-          // this is the name of the field in the original form that we're working on
-          form  = window.opener.document.${request/form/form/value};
-          field = '${request/form/property/value}';" >
-  </script>
- </head>
- <body class="body"
-       tal:content="structure python:utils.html_calendar (request)">
- </body>
-</html>
diff --git a/templates/minimal/html/_generic.collision.html b/templates/minimal/html/_generic.collision.html
deleted file mode 100644 (file)
index 2a2768a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> Edit Collision - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<tal:block metal:fill-slot="body_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> Edit Collision</tal:block>
-
-<td class="content" metal:fill-slot="content" i18n:translate="
-  There has been a collision. Another user updated this node
-  while you were editing. Please <a href='${context}'>reload</a>
-  the node and review your edits.
-"><span tal:replace="context/designator" i18n:name="context" />
-</td>
-</tal:block>
diff --git a/templates/minimal/html/_generic.help.html b/templates/minimal/html/_generic.help.html
deleted file mode 100644 (file)
index 069c0a6..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html tal:define="property request/form/property/value" >
-  <head>
-      <link rel="stylesheet" type="text/css" href="@@file/style.css" />
-      <meta http-equiv="Content-Type"
-       tal:attributes="content string:text/html;; charset=${request/client/charset}" />
-      <tal:block tal:condition="python:request.form.has_key('property')">
-      <title i18n:translate=""><tal:x i18n:name="property"
-       tal:content="property" i18n:translate="" /> help - <span i18n:name="tracker"
-       tal:replace="config/TRACKER_NAME" /></title>
-      <script language="Javascript" type="text/javascript"
-          tal:content="structure string:
-          // this is the name of the field in the original form that we're working on
-          form  = window.opener.document.${request/form/form/value};
-          field  = '${request/form/property/value}';">
-      </script>
-      <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="batch request/batch;
-                   props python:request.form['properties'].value.split(',')">
-
-     <div id="classhelp-controls">
-       <!--input type="button" name="btn_clear"
-              value="Clear" onClick="clearList()"/ -->
-       <input type="text" name="text_preview" size="24" class="preview"
-              onchange="reviseList(this.value);"/>
-       <input type="button" name="btn_reset"
-              value=" Cancel " onclick="resetList(); window.close();"
-              i18n:attributes="value" />
-       <input type="button" name="btn_apply" class="apply"
-              value=" Apply " onclick="updateList(); window.close();"
-              i18n:attributes="value" />
-     </div>
-     <table width="100%">
-      <tr class="navigation">
-       <th>
-        <a tal:define="prev batch/previous" tal:condition="prev"
-           tal:attributes="href python:request.indexargs_url(request.classname,
-           {'@template':'help', 'property': request.form['property'].value,
-            'properties': request.form['properties'].value,
-            'form': request.form['form'].value,
-            'type': request.form['type'].value,
-            '@startwith':prev.first, '@pagesize':prev.size})"
-           i18n:translate="" >&lt;&lt; previous</a>
-        &nbsp;
-       </th>
-       <th i18n:translate=""><span tal:replace="batch/start" i18n:name="start"
-        />..<span tal:replace="python: batch.start + batch.length -1" i18n:name="end"
-        /> out of <span tal:replace="batch/sequence_length" i18n:name="total"
-        />
-       </th>
-       <th>
-        <a tal:define="next batch/next" tal:condition="next"
-           tal:attributes="href python:request.indexargs_url(request.classname,
-           {'@template':'help', 'property': request.form['property'].value,
-            'properties': request.form['properties'].value,
-            'form': request.form['form'].value,
-            'type': request.form['type'].value,
-            '@startwith':next.first, '@pagesize':next.size})"
-           i18n:translate="" >next &gt;&gt;</a>
-        &nbsp;
-       </th>
-      </tr>
-     </table>
-
-     <table class="classhelp">
-       <tr>
-           <th>&nbsp;<b>x</b></th>
-           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
-       </tr>
-       <tr tal:repeat="item batch">
-         <tal:block tal:define="attr python:item[props[0]]" >
-           <td>
-             <input name="check"
-                 onclick="updatePreview();"
-                 tal:attributes="type python:request.form['type'].value;
-                                 value attr; id string:id_$attr" />
-             </td>
-             <td tal:repeat="prop props">
-                 <label class="classhelp-label"
-                        tal:attributes="for string:id_$attr"
-                        tal:content="python:item[prop]"></label>
-             </td>
-           </tal:block>
-       </tr>
-       <tr>
-           <th>&nbsp;<b>x</b></th>
-           <th tal:repeat="prop props" tal:content="prop" i18n:translate=""></th>
-       </tr>
-     </table>
-
- </form>
- </body>
-</html>
diff --git a/templates/minimal/html/_generic.index.html b/templates/minimal/html/_generic.index.html
deleted file mode 100644 (file)
index 81918ef..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
-
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<tal:block metal:fill-slot="body_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok()
- or request.user.hasRole('Anonymous'))"
- tal:omit-tag="python:1" i18n:translate=""
->You are not allowed to view this page.</span>
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())
- and request.user.hasRole('Anonymous')"
- tal:omit-tag="python:1" i18n:translate=""
->Please login with your username and password.</span>
-
-<tal:block tal:condition="context/is_edit_ok">
-<tal:block i18n:translate="">
-<p class="form-help">
- You may edit the contents of the
- <span tal:replace="request/classname" i18n:name="classname"/>
- class using this form. Commas, newlines and double quotes (") must be
- handled delicately. You may include commas and newlines by enclosing the
- values in double-quotes ("). Double quotes themselves must be quoted by
- doubling ("").
-</p>
-
-<p class="form-help">
- Multilink properties have their multiple values colon (":") separated
- (... ,"one:two:three", ...)
-</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>
-</tal:block>
-<form onSubmit="return submit_once()" method="POST"
-      tal:attributes="action context/designator">
-<textarea rows="15" style="width:90%" name="rows" tal:content="context/csv"></textarea>
-<br>
-<input type="hidden" name="@action" value="editCSV">
-<input type="submit" value="Edit Items" i18n:attributes="value">
-</form>
-</tal:block>
-
-<table tal:condition="context/is_only_view_ok" width="100%" class="list">
- <tr>
-  <th tal:repeat="property context/propnames" tal:content="property">&nbsp;</th>
- </tr>
- <tal:block repeat="item context/list">
- <tr tal:condition="item/is_view_ok"
-     tal:attributes="class python:['normal', 'alt'][repeat['item'].index%6/3]">
-  <td tal:repeat="property context/propnames"
-   tal:content="python: item[property] or default"
-  >&nbsp;</td>
-  </tr>
- </tal:block>
-</table>
-
-</td>
-
-</tal:block>
diff --git a/templates/minimal/html/_generic.item.html b/templates/minimal/html/_generic.item.html
deleted file mode 100644 (file)
index ac60acb..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<tal:block metal:fill-slot="body_title" i18n:translate=""
- ><span tal:replace="python:context._classname.capitalize()"
- i18n:name="class" /> editing</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok()
- or request.user.hasRole('Anonymous'))"
- tal:omit-tag="python:1" i18n:translate=""
->You are not allowed to view this page.</span>
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())
- and request.user.hasRole('Anonymous')"
- tal:omit-tag="python:1" i18n:translate=""
->Please login with your username and password.</span>
-
-<form method="POST" onSubmit="return submit_once()"
-      enctype="multipart/form-data" tal:condition="context/is_edit_ok"
-      tal:attributes="action context/designator">
-
-<input type="hidden" name="@template" value="item">
-
-<table class="form">
-
-<tr tal:repeat="prop python:db[context._classname].properties()">
- <tal:block tal:condition="python:prop._name not in ('id',
-   'creator', 'creation', 'actor', 'activity')">
-  <th tal:content="prop/_name"></th>
-  <td tal:content="structure python:context[prop._name].field()"></td>
- </tal:block>
-</tr>
-<tr>
- <td>&nbsp;</td>
- <td colspan=3 tal:content="structure context/submit">
-  submit button will go here
- </td>
-</tr>
-</table>
-
-</form>
-
-<table class="form" tal:condition="context/is_only_view_ok">
-
-<tr tal:repeat="prop python:db[context._classname].properties()">
- <tal:block tal:condition="python:prop._name not in ('id', 'creator',
-                                  'creation', 'activity')">
-  <th tal:content="prop/_name"></th>
-  <td tal:content="structure python:context[prop._name].field()"></td>
- </tal:block>
-</tr>
-</table>
-
-
-<tal:block tal:condition="python:context.id and context.is_view_ok()">
- <tal:block tal:replace="structure context/history" />
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/templates/minimal/html/help_controls.js b/templates/minimal/html/help_controls.js
deleted file mode 100644 (file)
index d3b5529..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-// initial values for either Nosy, Superseder, Keyword and Waiting On,
-// depending on which has called
-original_field = form[field].value;
-
-// Some browsers (ok, IE) don't define the "undefined" variable.
-undefined = document.geez_IE_is_really_friggin_annoying;
-
-function trim(value) {
-  var temp = value;
-  var obj = /^(\s*)([\W\w]*)(\b\s*$)/;
-  if (obj.test(temp)) { temp = temp.replace(obj, '$2'); }
-  var obj = /  /g;
-  while (temp.match(obj)) { temp = temp.replace(obj, " "); }
-  return temp;
-}
-
-function determineList() {
-    // generate a comma-separated list of the checked items
-    var list = new String('');
-    for (box=0; box < document.frm_help.check.length; box++) {
-        if (document.frm_help.check[box].checked) {
-            if (list.length == 0) {
-                separator = '';
-            }
-            else {
-                separator = ',';
-            }
-            // we used to use an Array and push / join, but IE5.0 sux
-            list = list + separator + document.frm_help.check[box].value;
-        }
-    }
-    return list;
-}
-
-function updateList() {
-  // write back to opener window
-  if (document.frm_help.check==undefined) { return; }
-  form[field].value = determineList();
-}
-
-function updatePreview() {
-  // update the preview box
-  if (document.frm_help.check==undefined) { return; }
-  writePreview(determineList());
-}
-
-function clearList() {
-  // uncheck all checkboxes
-  if (document.frm_help.check==undefined) { return; }
-  for (box=0; box < document.frm_help.check.length; box++) {
-      document.frm_help.check[box].checked = false;
-  }
-}
-
-function reviseList(vals) {
-  // update the checkboxes based on the preview field
-  if (document.frm_help.check==undefined) { return; }
-  var to_check;
-  var list = vals.split(",");
-  if (document.frm_help.check.length==undefined) {
-      check = document.frm_help.check;
-      to_check = false;
-      for (val in list) {
-          if (check.value==trim(list[val])) {
-              to_check = true;
-              break;
-          }
-      }
-      check.checked = to_check;
-  } else {
-    for (box=0; box < document.frm_help.check.length; box++) {
-      check = document.frm_help.check[box];
-      to_check = false;
-      for (val in list) {
-          if (check.value==trim(list[val])) {
-              to_check = true;
-              break;
-          }
-      }
-      check.checked = to_check;
-    }
-  }
-}
-
-function resetList() {
-  // reset preview and check boxes to initial values
-  if (document.frm_help.check==undefined) { return; }
-  writePreview(original_field);
-  reviseList(original_field);
-}
-
-function writePreview(val) {
-   // writes a value to the text_preview
-   document.frm_help.text_preview.value = val;
-}
-
-function focusField(name) {
-    for(i=0; i < document.forms.length; ++i) {
-      var obj = document.forms[i].elements[name];
-      if (obj && obj.focus) {obj.focus();}
-    }
-}
-
-function selectField(name) {
-    for(i=0; i < document.forms.length; ++i) {
-      var obj = document.forms[i].elements[name];
-      if (obj && obj.focus){obj.focus();} 
-      if (obj && obj.select){obj.select();}
-    }
-}
-
diff --git a/templates/minimal/html/home.classlist.html b/templates/minimal/html/home.classlist.html
deleted file mode 100644 (file)
index 930306b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">List of classes - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">List of classes</span>
-<td class="content" metal:fill-slot="content">
-<table class="classlist">
-
-<tal:block tal:repeat="cl db/classes">
- <tr>
-  <th class="header" colspan="2" align="left">
-   <a tal:attributes="href string:${cl/classname}"
-      tal:content="python:cl.classname.capitalize()">classname</a>
-  </th>
- </tr>
- <tr tal:repeat="prop cl/properties">
-  <th tal:content="prop/_name">name</th>
-  <td tal:content="prop/_prop">type</td>
- </tr>
-</tal:block>
-
-</table>
-</td>
-
-</tal:block>
diff --git a/templates/minimal/html/home.html b/templates/minimal/html/home.html
deleted file mode 100644 (file)
index c933c59..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">Tracker home - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Tracker home</span>
-<td class="content" metal:fill-slot="content">
-
-<!--
- This is the default body that is displayed when people visit the
- tracker. The tag below lists the currently open issues. You may
- replace it with a greeting message, or a different list of issues or
- whatever. It's a good idea to have the issues on the front page though
--->
-
-<tal:block tal:define="anon python:request.user.username == 'anonymous'">
-<p tal:condition="not:anon" class="help" i18n:translate="">
-Please select from one of the menu options on the left.
-</p>
-<p tal:condition="anon" class="help" i18n:translate="">
-Please log in or register.
-</p>
-</tal:block>
-
-</td>
-</tal:block>
diff --git a/templates/minimal/html/page.html b/templates/minimal/html/page.html
deleted file mode 100644 (file)
index dbbbb5e..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-<!-- vim:sw=2 sts=2
---><tal:block metal:define-macro="icing"
-><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title metal:define-slot="head_title">title goes here</title>
-<link rel="stylesheet" type="text/css" href="@@file/style.css">
-<meta http-equiv="Content-Type"
- tal:attributes="content string:text/html;; charset=${request/client/charset}" />
-<script tal:replace="structure request/base_javascript">
-</script>
-<metal:x define-slot="more-javascript" />
-
-</head>
-<body class="body">
-
-<table class="body"
- tal:define="
-kw_edit python:request.user.hasPermission('Edit', 'keyword');
-kw_create python:request.user.hasPermission('Create', 'keyword');
-kw_edit_link python:kw_edit and db.keyword.list();
-columns string:id,activity,title,creator,status;
-columns_showall string:id,activity,title,creator,assignedto,status;
-status_notresolved string:-1,1,2,3,4,5,6,7;
-"
->
-
-<tr>
- <td class="page-header-left">&nbsp;</td>
- <td class="page-header-top">
-   <div id="body-title">
-     <h2><span metal:define-slot="body_title">body title</span></h2>
-   </div>
-   <div id="searchbox">
-     <form method="GET" action="issue">
-       <input type="hidden" name="@columns"
-             tal:attributes="value columns_showall"
-             value="id,activity,title,creator,assignedto,status"/>
-       <input type="hidden" name="@sort" value="activity"/>
-       <input type="hidden" name="@group" value="priority"/>
-       <input id="search-text" name="@search_text" size="10"
-              tal:attributes="value request/search_text"/>
-       <input type="submit" id="submit" name="submit" value="Search" i18n:attributes="value" />
-     </form>
-  </div>
- </td>
-</tr>
-
-<tr>
- <td rowspan="2" valign="top" class="sidebar">
-  <p class="classblock"
-     tal:condition="python:request.user.hasPermission('View', 'query')">
-   <span i18n:translate=""
-    ><b>Your Queries</b> (<a href="query?@template=edit">edit</a>)</span><br>
-   <tal:block tal:repeat="qs request/user/queries">
-    <a href="#" tal:attributes="href string:${qs/klass}?${qs/url}&@dispname=${qs/name}"
-       tal:content="qs/name">link</a><br>
-   </tal:block>
-  </p>
-
-  <form method="POST" tal:attributes="action request/base">
-   <p class="classblock"
-       tal:condition="python:request.user.hasPermission('View', 'issue')">
-    <b i18n:translate="">Issues</b><br>
-    <span tal:condition="python:request.user.hasPermission('Create', 'issue')">
-      <a href="issue?@template=item" i18n:translate="">Create New</a><br>
-    </span>
-    <a href="#"
-       tal:attributes="href python:request.indexargs_url('issue', {
-      '@sort': '-activity',
-      '@group': 'priority',
-      '@filter': 'status,assignedto',
-      '@columns': columns,
-      '@search_text': '',
-      'status': status_notresolved,
-      'assignedto': '-1',
-      '@dispname': i18n.gettext('Show Unassigned'),
-     })"
-       i18n:translate="">Show Unassigned</a><br>
-    <a href="#"
-       tal:attributes="href python:request.indexargs_url('issue', {
-      '@sort': '-activity',
-      '@group': 'priority',
-      '@filter': 'status',
-      '@columns': columns_showall,
-      '@search_text': '',
-      'status': status_notresolved,
-      '@dispname': i18n.gettext('Show All'),
-     })"
-       i18n:translate="">Show All</a><br>
-    <a href="issue?@template=search" i18n:translate="">Search</a><br>
-    <input type="submit" class="form-small" value="Show issue:"
-     i18n:attributes="value"><input class="form-small" size="4"
-     type="text" name="@number">
-    <input type="hidden" name="@type" value="issue">
-    <input type="hidden" name="@action" value="show">
-   </p>
-  </form>
-
-  <p class="classblock"
-     tal:condition="python:kw_edit or kw_create">
-   <b i18n:translate="">Keywords</b><br>
-   <span tal:condition="python:request.user.hasPermission('Create', 'keyword')">
-    <a href="keyword?@template=item" i18n:translate="">Create New</a><br>
-   </span>
-   <span tal:condition="kw_edit_link">
-    <a href="keyword?@template=item" i18n:translate="">Edit Existing</a><br>
-   </span>
-  </p>
-
-  <p class="classblock"
-       tal:condition="python:request.user.hasPermission('View', 'user')">
-   <b i18n:translate="">Administration</b><br>
-   <span tal:condition="python:request.user.hasPermission('Edit', None)">
-    <a href="home?@template=classlist" i18n:translate="">Class List</a><br>
-   </span>
-   <span tal:condition="python:request.user.hasPermission('View', 'user')
-                            or request.user.hasPermission('Edit', 'user')">
-    <a href="user"  i18n:translate="">User List</a><br>
-   </span>
-   <a tal:condition="python:request.user.hasPermission('Create', 'user')"
-      href="user?@template=item" i18n:translate="">Add User</a>
-  </p>
-
-  <form method="POST" tal:condition="python:request.user.username=='anonymous'"
-        tal:attributes="action request/base">
-   <p class="userblock">
-    <b i18n:translate="">Login</b><br>
-    <input size="10" name="__login_name"><br>
-    <input size="10" type="password" name="__login_password"><br>
-    <input type="hidden" name="@action" value="Login">
-    <input type="checkbox" name="remember" id="remember">
-    <label for="remember" i18n:translate="">Remember me?</label><br>
-    <input type="submit" value="Login" i18n:attributes="value"><br>
-    <input type="hidden" name="__came_from" tal:attributes="value string:${request/base}${request/env/PATH_INFO}">
-    <span tal:replace="structure request/indexargs_form" />
-    <a href="user?@template=register"
-       tal:condition="python:request.user.hasPermission('Create', 'user')"
-     i18n:translate="">Register</a><br>
-    <a href="user?@template=forgotten" i18n:translate="">Lost&nbsp;your&nbsp;login?</a><br>
-   </p>
-  </form>
-
-  <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
-   <b i18n:translate="">Hello, <span i18n:name="user"
-    tal:replace="python:request.user.username.plain(escape=1)">username</span></b><br>
-   <a href="#" tal:attributes="href string:user${request/user/id}"
-    i18n:translate="">Your Details</a><br>
-   <a href="#" tal:attributes="href python:request.indexargs_url('',
-       {'@action':'logout'})" i18n:translate="">Logout</a>
-  </p>
-  <p class="userblock">
-   <b i18n:translate="">Help</b><br>
-   <a href="http://roundup.sourceforge.net/doc-1.0/"
-    i18n:translate="">Roundup docs</a>
-  </p>
- </td>
- <td>
-  <p tal:condition="options/error_message | nothing" class="error-message"
-     tal:repeat="m options/error_message" tal:content="structure m" />
-  <p tal:condition="options/ok_message | nothing" class="ok-message">
-    <span tal:repeat="m options/ok_message"
-       tal:content="structure string:$m <br/ > " />
-     <a class="form-small" tal:attributes="href request/current_url"
-        i18n:translate="">clear this message</a>
-  </p>
- </td>
-</tr>
-<tr>
- <td class="content" metal:define-slot="content">Page content goes here</td>
-</tr>
-
-</table>
-
-<pre tal:condition="request/form/debug | nothing" tal:content="request">
-</pre>
-
-</body>
-</html>
-</tal:block>
-
-<!--
-The following macros are intended to be used in search pages.
-
-The invoking context must define a "name" variable which names the
-property being searched.
-
-See issue.search.html in the classic template for examples.
--->
-
-<!-- creates a th and a label: -->
-<th metal:define-macro="th_label"
-    tal:define="required required | python:[]"
-    tal:attributes="class python:(name in required) and 'required' or nothing">
-  <label tal:attributes="for name" tal:content="label" i18n:translate="">text</label>
-       <metal:x define-slot="behind_the_label" />
-</th>
-
-<td metal:define-macro="search_input">
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-</td>
-
-<td metal:define-macro="search_date">
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-  <a class="classhelp"
-        tal:attributes="href python:'''javascript:help_window('issue?@template=calendar&property=%s&form=itemSynopsis', 300, 200)'''%name">(cal)</a>
-</td>
-
-<td metal:define-macro="search_popup">
-  <!--
-    context needs to specify the popup "columns" as a comma-separated
-    string (eg. "id,title" or "id,name,description") as well as name
-  -->
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-  <span tal:replace="structure python:db.issue.classhelp(columns,
-                                      property=name)" />
-</td>
-
-<td metal:define-macro="search_select">
-  <select tal:attributes="name name; id name"
-          tal:define="value python:request.form.getvalue(name)">
-    <option value="" i18n:translate="">don't care</option>
-    <metal:slot define-slot="extra_options" />
-    <option value="" i18n:translate="" disabled="disabled">------------</option>
-    <option tal:repeat="s python:db[db_klass].list()"
-            tal:attributes="value s/id; selected python:value == s.id"
-            tal:content="python:s[db_content]"></option>
-  </select>
-</td>
-
-<!-- like search_select, but translates the further values.
-Could extend it (METAL 1.1 attribute "extend-macro")
--->
-<td metal:define-macro="search_select_translated">
-  <select tal:attributes="name name; id name"
-          tal:define="value python:request.form.getvalue(name)">
-    <option value="" i18n:translate="">don't care</option>
-    <metal:slot define-slot="extra_options" />
-    <option value="" i18n:translate="" disabled="disabled">------------</option>
-    <option tal:repeat="s python:db[db_klass].list()"
-            tal:attributes="value s/id; selected python:value == s.id"
-                                               tal:content="python:s[db_content]"
-                                               i18n:translate=""></option>
-  </select>
-</td>
-
-<!-- currently, there is no convenient API to get a list of all roles -->
-<td metal:define-macro="search_select_roles"
-         tal:define="onchange onchange | nothing">
-  <select name=roles id=roles tal:attributes="onchange onchange">
-    <option value="" i18n:translate="">don't care</option>
-    <option value="" i18n:translate="" disabled="disabled">------------</option>
-    <option value="User">User</option>
-    <option value="Admin">Admin</option>
-    <option value="Anonymous">Anonymous</option>
-  </select>
-</td>
-
-<td metal:define-macro="search_multiselect">
-  <input tal:attributes="value python:request.form.getvalue(name) or nothing;
-                         name name;
-                         id name">
-  <span tal:replace="structure python:db[db_klass].classhelp(db_content,
-                                        property=name, width='600')" />
-</td>
-
-<td metal:define-macro="search_checkboxes">
- <ul class="search-checkboxes"
-     tal:define="value python:request.form.getvalue(name);
-                 values python:value and value.split(',') or []">
- <li tal:repeat="s python:db[db_klass].list()">
-  <input type="checkbox" tal:attributes="name name; id string:$name-${s/id};
-    value s/id; checked python:s.id in values" />
-  <label tal:attributes="for string:$name-${s/id}"
-         tal:content="python:s[db_content]" />
- </li>
- <li metal:define-slot="no_value_item">
-  <input type="checkbox" value="-1" tal:attributes="name name;
-     id string:$name--1; checked python:value == '-1'" />
-  <label tal:attributes="for string:$name--1" i18n:translate="">no value</label>
- </li>
- </ul>
-</td>
-
-<td metal:define-macro="column_input">
-  <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"
-         tal:attributes="value name;
-                         checked python:name == sort_on">
-</td>
-
-<td metal:define-macro="group_input">
-  <input type="radio" name="@group"
-         tal:attributes="value name;
-                         checked python:name == group_on">
-</td>
-
-<!--
-The following macros are intended for user editing.
-
-The invoking context must define a "name" variable which names the
-property being searched; the "edit_ok" variable tells whether the
-current user is allowed to edit.
-
-See user.item.html in the classic template for examples.
--->
-<script metal:define-macro="user_utils" type="text/javascript" src="@@file/user_utils.js"></script>
-
-<!-- src: value will be re-used for other input fields -->
-<input metal:define-macro="user_src_input"
-    type="text" tal:attributes="onblur python:edit_ok and 'split_name(this)';
-    id name; name name; value value; readonly not:edit_ok"
-    value="heinz.kunz">
-<!-- normal: no re-using -->
-<input metal:define-macro="user_normal_input" type="text"
-    tal:attributes="id name; name name; value value; readonly not:edit_ok"
-    value="heinz">
-<!-- password: type; no initial value -->
-    <input metal:define-macro="user_pw_input" type="password"
-    tal:attributes="id name; name name; readonly not:edit_ok" value="">
-    <input metal:define-macro="user_confirm_input" type="password"
-    tal:attributes="id name; name string:@confirm@$name; readonly not:edit_ok" value="">
-
diff --git a/templates/minimal/html/style.css b/templates/minimal/html/style.css
deleted file mode 100644 (file)
index f7d7eb4..0000000
+++ /dev/null
@@ -1,423 +0,0 @@
-/* main page styles */
-body.body {
-  font-family: sans-serif, Arial, Helvetica;
-  background-color: white;
-  color: #333;
-  margin: 0;
-}
-a[href]:hover {
-  color:blue;
-  text-decoration: underline;
-}
-a[href], a[href]:link {
-  color:blue;
-  text-decoration: none;
-}
-
-table.body {
-  border: 0;
-  padding: 0;
-  border-spacing: 0;
-  border-collapse: separate;
-}
-
-td.page-header-left {
-  padding: 5px;
-  border-bottom: 1px solid #444;
-}
-td.sidebar {
-  padding: 1px 0 0 1px;
-  white-space: nowrap;
-}
-
-/* don't display the sidebar when printing */
-@media print {
-    td.page-header-left {
-        display: none;
-    }
-    td.sidebar {
-        display: none;
-    }
-    .index-controls {
-        display: none;
-    }
-    #searchbox {
-        display: none;
-    }
-}
-
-td.page-header-top {
-  padding: 5px;
-  border-bottom: 1px solid #444;
-}
-#searchbox {
-    float: right;
-}
-
-div#body-title {
-  float: left;
-}
-
-
-div#searchbox {
-  float: right;
-  padding-top: 1em;
-}
-
-div#searchbox input#search-text {
-  width: 10em;
-}
-
-form {
-  margin: 0;
-}
-
-textarea {
-    font-family: monospace;
-}
-
-td.sidebar p.classblock {
-  padding: 2px 5px 2px 5px;
-  margin: 1px;
-  border: 1px solid #444;
-  background-color: #eee;
-}
-
-td.sidebar p.userblock {
-  padding: 2px 5px 2px 5px;
-  margin: 1px 1px 1px 1px;
-  border: 1px solid #444;
-  background-color: #eef;
-}
-
-.form-small {
-  padding: 0;
-  font-size: 75%;
-}
-
-
-td.content {
-  padding: 1px 5px 1px 5px;
-  vertical-align: top;
-  width: 100%;
-}
-
-td.date, th.date { 
-  white-space: nowrap;
-}
-
-p.ok-message {
-  background-color: #22bb22;
-  padding: 5px;
-  color: white;
-  font-weight: bold;
-}
-p.error-message {
-  background-color: #bb2222;
-  padding: 5px;
-  color: white;
-  font-weight: bold;
-}
-p.error-message a[href] {
-  color: white;
-  text-decoration: underline;
-}
-
-
-/* style for search forms */
-ul.search-checkboxes {
-    display: inline;
-    padding: none;
-    list-style: none;
-}
-ul.search-checkboxes > li {
-    display: inline;
-    padding-right: .5em;
-}
-
-
-/* style for forms */
-table.form {
-  padding: 2px;
-  border-spacing: 0;
-  border-collapse: separate;
-}
-
-table.form th {
-  color: #338;
-  text-align: right;
-  vertical-align: top;
-  font-weight: normal;
-  white-space: nowrap;
-}
-
-table.form th.header {
-  font-weight: bold;
-  background-color: #eef;
-  text-align: left;
-}
-
-table.form th.required {
-  font-weight: bold;
-}
-
-table.form td {
-  color: #333;
-  empty-cells: show;
-  vertical-align: top;
-}
-
-table.form td.optional {
-  font-weight: bold;
-  font-style: italic;
-}
-
-table.form td.html {
-  color: #777;
-}
-
-/* style for lists */
-table.list {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.list th {
-  padding: 0 4px 0 4px;
-  color: #404070;
-  background-color: #eef;
-  border: 1px solid white;
-  vertical-align: top;
-  empty-cells: show;
-}
-table.list th a[href]:hover { color: #404070 }
-table.list th a[href]:link { color: #404070 }
-table.list th a[href] { color: #404070 }
-table.list th.group {
-  background-color: #f4f4ff;
-  text-align: center;
-}
-
-table.list td {
-  padding: 0 4px 0 4px;
-  border: 1px solid white;
-  color: #404070;
-  background-color: #efefef;
-  vertical-align: top;
-  empty-cells: show;
-}
-
-table.list tr.navigation th {
-  width: 33%;
-  border-style: hidden;
-  text-align: center;
-}
-table.list tr.navigation td {
-    border: none
-}
-table.list tr.navigation th:first-child {
-  text-align: left;
-}
-table.list tr.navigation th:last-child {
-  text-align: right;
-}
-
-
-/* style for message displays */
-table.messages {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.messages th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.messages th {
-  font-weight: bold;
-  color: black;
-  text-align: left;
-  border-bottom: 1px solid #afafaf;
-}
-
-table.messages td {
-  font-family: monospace;
-  background-color: #efefef;
-  border-bottom: 1px solid #afafaf;
-  color: black;
-  empty-cells: show;
-  border-right: 1px solid #afafaf;
-  vertical-align: top;
-  padding: 2px 5px 2px 5px;
-}
-
-table.messages td:first-child {
-  border-left: 1px solid #afafaf;
-  border-right: 1px solid #afafaf;
-}
-
-/* style for file displays */
-table.files {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.files th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.files th {
-  border-bottom: 1px solid #afafaf;
-  font-weight: bold;
-  text-align: left;
-}
-
-table.files td {
-  font-family: monospace;
-  empty-cells: show;
-}
-
-/* style for history displays */
-table.history {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.history th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-  font-size: 100%;
-}
-
-table.history th {
-  border-bottom: 1px solid #afafaf;
-  font-weight: bold;
-  text-align: left;
-  font-size: 90%;
-}
-
-table.history td {
-  font-size: 90%;
-  vertical-align: top;
-  empty-cells: show;
-}
-
-
-/* style for class list */
-table.classlist {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.classlist th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.classlist th {
-  font-weight: bold;
-  text-align: left;
-}
-
-
-/* style for class help display */
-table.classhelp {      /* the table-layout: fixed;        */ 
-  table-layout: fixed; /* compromises quality for speed   */
-  overflow: hidden;
-  font-size: .9em;
-  padding-bottom: 3em;
-}
-
-table.classhelp th {
-  font-weight: normal;
-  text-align: left;
-  color: #444;
-  background-color: #efefef;
-  border-bottom: 1px solid #afafaf;
-  border-top: 1px solid #afafaf;
-  text-transform: uppercase;
-  vertical-align: middle;
-  line-height:1.5em;
-}
-
-table.classhelp td {
-  vertical-align: middle;
-  padding-right: .2em;
-  border-bottom: 1px solid #efefef;
-  text-align: left;
-  empty-cells: show;
-  white-space: nowrap;
-  vertical-align: middle;
-}
-
-table.classhelp tr:hover {
-  background-color: #eee;
-}
-
-label.classhelp-label {
-  cursor: pointer;
-}
-
-#classhelp-controls {
-  position: fixed;
-  display: block;
-  top: auto;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  padding: .5em;
-  border-top: 2px solid #444;
-  background-color: #eee;
-}
-
-#classhelp-controls input.apply {
-  width: 7em;
-  font-weight: bold;
-  margin-right: 2em;
-  margin-left: 2em;
-}
-
-#classhelp-controls input.preview {
-   margin-right: 3em;
-   margin-left: 1em;
-}
-
-/* style for "other" displays */
-table.otherinfo {
-  border-spacing: 0;
-  border-collapse: separate;
-  width: 100%;
-}
-
-table.otherinfo th.header{
-  padding-top: 10px;
-  border-bottom: 1px solid gray;
-  font-weight: bold;
-  background-color: white;
-  color: #707040;
-}
-
-table.otherinfo th {
-  border-bottom: 1px solid #afafaf;
-  font-weight: bold;
-  text-align: left;
-}
diff --git a/templates/minimal/html/user.index.html b/templates/minimal/html/user.index.html
deleted file mode 100644 (file)
index f0a84b8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<!-- dollarId: user.index,v 1.3 2002/07/09 05:29:51 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title" i18n:translate="">User listing - <span
- i18n:name="tracker" tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">User listing</span>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))"
- i18n:translate="">You are not allowed to view this page.</span>
-
-<span tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')"
- i18n:translate="">Please login with your username and password.</span>
-
-<table width="100%" tal:condition="context/is_view_ok" class="list">
-<tr>
- <th i18n:translate="">Username</th>
- <th i18n:translate="">Email address</th>
-</tr>
-<tal:block repeat="user context/list">
- <tr tal:condition="user/is_view_ok"
-    tal:attributes="class python:['normal', 'alt'][repeat['user'].index%6/3]">
- <td>
-  <a tal:attributes="href string:user${user/id}"
-     tal:content="user/username">username</a>
- </td>
- <td tal:content="python:user.address.email()">address</td>
- </tr>
-</tal:block>
-</table>
-</td>
-
-</tal:block>
diff --git a/templates/minimal/html/user.item.html b/templates/minimal/html/user.item.html
deleted file mode 100644 (file)
index bafccd2..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:doc metal:use-macro="templates/page/macros/icing"
-define="edit_ok context/is_edit_ok"
->
-<title metal:fill-slot="head_title">
-<tal:if condition="context/id" i18n:translate=""
- >User <tal:x content="context/id" i18n:name="id"
- />: <tal:x content="context/username" i18n:name="title"
- /> - <tal:x content="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:if>
-<tal:if condition="not:context/id" i18n:translate=""
- >New User - <span tal:replace="config/TRACKER_NAME" i18n:name="tracker"
-/></tal:if>
-</title>
-<metal:slot fill-slot="more-javascript">
-<script metal:use-macro="templates/page/macros/user_utils"></script>
-<script type="text/javascript" src="@@file/help_controls.js"></script>
-</metal:slot>
-<tal:block metal:fill-slot="body_title"
-  define="edit_ok context/is_edit_ok">
- <span tal:condition="python: not (context.id or edit_ok)"
-  tal:omit-tag="python:1" i18n:translate="">New User</span>
- <span tal:condition="python: not context.id and edit_ok"
-  tal:omit-tag="python:1" i18n:translate="">New User Editing</span>
- <span tal:condition="python: context.id and not edit_ok"
-  tal:omit-tag="python:1" i18n:translate="">User<tal:x
-  replace="context/id" i18n:name="id" /></span>
- <span tal:condition="python: context.id and edit_ok"
-  tal:omit-tag="python:1" i18n:translate="">User<tal:x
-  replace="context/id" i18n:name="id" /> Editing</span>
-</tal:block>
-
-<td class="content" metal:fill-slot="content">
-
-<p tal:condition="python:not (context.is_view_ok()
- or request.user.hasRole('Anonymous'))" i18n:translate="">
- You are not allowed to view this page.</p>
-
-<p tal:condition="python:not context.is_view_ok()
- and request.user.hasRole('Anonymous')" i18n:translate="">
- Please login with your username and password.</p>
-
-<div tal:condition="context/is_view_ok">
-
-<form method="POST"
-      name="itemSynopsis"
-      tal:define="required python:'username address'.split()"
-      enctype="multipart/form-data"
-      tal:attributes="action context/designator;
-      onSubmit python:'return checkRequiredFields(\'%s\')'%'\', \''.join(required);
-      ">
-<table class="form" tal:define="
-  th_label templates/page/macros/th_label;
-  src_input templates/page/macros/user_src_input;
-  normal_input templates/page/macros/user_normal_input;
-  pw_input templates/page/macros/user_pw_input;
-  confirm_input templates/page/macros/user_confirm_input;
-  edit_ok context/is_edit_ok;
-  ">
- <tr tal:define="name string:realname; label string:Name; value context/realname; edit_ok edit_ok">
-  <th metal:use-macro="th_label">Name</th>
-  <td><input name="realname" metal:use-macro="src_input"></td>
- </tr>
- <tr tal:define="name string:username; label string:Login Name; value context/username">
-   <th metal:use-macro="th_label">Login Name</th>
-   <td><input metal:use-macro="src_input"></td>
- </tr>
- <tal:if condition="edit_ok">
- <tr tal:define="name string:password; label string:Login Password">
-  <th metal:use-macro="th_label">Login Password</th>
-  <td><input metal:use-macro="pw_input" type="password"></td>
- </tr>
- <tr tal:define="name string:password; label string:Confirm Password">
-  <th metal:use-macro="th_label">Confirm Password</th>
-  <td><input metal:use-macro="confirm_input" type="password"></td>
- </tr>
- </tal:if>
- <tal:if condition="python:request.user.hasPermission('Web Roles')">
- <tr tal:define="name string:roles; label string:Roles;">
-  <th><label for="roles" i18n:translate="">Roles</label></th>
-  <td tal:define="gips context/id">
-    <tal:subif condition=gips define="value context/roles">
-      <input metal:use-macro="normal_input">
-    </tal:subif>
-    <tal:subif condition="not:gips" define="value db/config/NEW_WEB_USER_ROLES">
-      <input metal:use-macro="normal_input">
-    </tal:subif>
-   <tal:block i18n:translate="">(to give the user more than one role,
-    enter a comma,separated,list)</tal:block>
-  </td>
- </tr>
- </tal:if>
-
- <tr tal:define="name string:phone; label string:Phone; value context/phone">
-  <th metal:use-macro="th_label">Phone</th>
-  <td><input name="phone" metal:use-macro="normal_input"></td>
- </tr>
-
- <tr tal:define="name string:organisation; label string:Organisation; value context/organisation">
-  <th metal:use-macro="th_label">Organisation</th>
-  <td><input name="organisation" metal:use-macro="normal_input"></td>
- </tr>
-
- <tr tal:condition="python:edit_ok or context.timezone"
-     tal:define="name string:timezone; label string:Timezone; value context/timezone">
-  <th metal:use-macro="th_label">Timezone</th>
-  <td><input name="timezone" metal:use-macro="normal_input">
-   <tal:block tal:condition="edit_ok" i18n:translate="">(this is a numeric hour offset, the default is
-    <span tal:replace="db/config/DEFAULT_TIMEZONE" i18n:name="zone"
-    />)</tal:block>
-  </td>
- </tr>
-
- <tr tal:define="name string:address; label string:E-mail address; value context/address">
-  <th metal:use-macro="th_label">E-mail address</th>
-  <td tal:define="mailto python:context.address.field(id='address');
-         mklink python:mailto and not edit_ok">
-      <a href="mailto:calvin@the-z.org"
-                 tal:attributes="href string:mailto:$value"
-                 tal:content="value"
-          tal:condition="python:mklink">calvin@the-z.org</a>
-      <tal:if condition=edit_ok>
-      <input metal:use-macro="src_input" value="calvin@the-z.org">
-      </tal:if>
-      &nbsp;
-  </td>
- </tr>
-
- <tr>
-  <th><label for="alternate_addresses" i18n:translate="">Alternate E-mail addresses<br>One address per line</label></th>
-  <td>
-    <textarea rows=5 cols=40 tal:replace="structure context/alternate_addresses/multiline">nobody@nowhere.org
-anybody@everywhere.net
-(alternate_addresses)
-    </textarea>
-  </td>
- </tr>
-
- <tr tal:condition="edit_ok">
-  <td>
-   &nbsp;
-   <input type="hidden" name="@template" value="item">
-   <input type="hidden" name="@required" value="username,address"
-          tal:attributes="value python:','.join(required)">
-  </td>
-  <td><input type="submit" value="save" tal:replace="structure context/submit"><!--submit button here-->
-    <input type=reset>
-  </td>
- </tr>
-</table>
-</form>
-
-<tal:block tal:condition="not:context/id" i18n:translate="">
-<table class="form">
-<tr>
- <td>Note:&nbsp;</td>
- <th class="required">highlighted</th>
- <td>&nbsp;fields are required.</td>
-</tr>
-</table>
-</tal:block>
-
-<tal:block tal:condition="context/id" tal:replace="structure context/history" />
-
-</div>
-
-</td>
-
-</tal:doc>
diff --git a/templates/minimal/html/user.register.html b/templates/minimal/html/user.register.html
deleted file mode 100644 (file)
index 7e7a5d3..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<!-- dollarId: user.item,v 1.7 2002/08/16 04:29:04 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title"
- i18n:translate="">Registering with <span i18n:name="tracker"
- tal:replace="db/config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Registering with <span i18n:name="tracker"
- tal:replace="db/config/TRACKER_NAME" /></span>
-<td class="content" metal:fill-slot="content">
-
-<tal:block tal:define=" editok python:request.user.username=='anonymous' and
-           request.user.hasPermission('Web Registration')">
-
-<span tal:condition="python:not (editok or request.user.hasRole('Anonymous'))"
- i18n:translate="">You are not allowed to view this page.</span>
-
-<span tal:condition="python:not editok and request.user.hasRole('Anonymous')"
- i18n:translate="">Please login with your username and password.</span>
-
-<tal:block tal:condition="editok">
-<form method="POST" onSubmit="return submit_once()" enctype="multipart/form-data">
-<input type="hidden" name=":template" value="register">
-<input type="hidden" name=":required" value="username">
-<input type="hidden" name=":required" value="password">
-<input type="hidden" name=":required" value="address">
-
-<table class="form">
- <tr>
-  <th i18n:translate="">Login Name</th>
-  <td tal:content="structure context/username/field">username</td>
- </tr>
- <tr>
-  <th i18n:translate="">Login Password</th>
-  <td tal:content="structure context/password/field">password</td>
- </tr>
- <tr>
-  <th i18n:translate="">Confirm Password</th>
-  <td tal:content="structure context/password/confirm">password</td>
- </tr>
- <tr tal:condition="python:request.user.hasPermission('Web Roles')">
-  <th i18n:translate="">Roles</th>
-  <td tal:condition="exists:item"
-      tal:content="structure context/roles/field">roles</td>
-  <td tal:condition="not:exists:item">
-   <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
-  </td>
- </tr>
- <tr>
-  <th i18n:translate="">E-mail address</th>
-  <td tal:content="structure context/address/field">address</td>
- </tr>
- <tr>
-  <th i18n:translate="">Alternate E-mail addresses<br>One address per line</th>
-  <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
- </tr>
-
- <tr>
-  <td>&nbsp;</td>
-  <td>
-   <input type="hidden" name=":action" value="register">
-   <input type="submit" name="submit" value="Register" i18n:attributes="value">
-  </td>
- </tr>
-</table>
-</form>
-
-</tal:block>
-
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/templates/minimal/html/user.rego_progress.html b/templates/minimal/html/user.rego_progress.html
deleted file mode 100644 (file)
index 4d6bfe4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title"
- i18n:translate="">Registration in progress - <span i18n:name="tracker"
- tal:replace="config/TRACKER_NAME" /></title>
-<span metal:fill-slot="body_title" tal:omit-tag="python:1"
- i18n:translate="">Registration in progress...</span>
-<td class="content" metal:fill-slot="content">
-
-<p i18n:translate="">You will shortly receive an email
-to confirm your registration. To complete the registration process,
-visit the link indicated in the email.
-</p>
-
-</td>
-</tal:block>
diff --git a/templates/minimal/initial_data.py b/templates/minimal/initial_data.py
deleted file mode 100644 (file)
index 28bfefe..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# TRACKER DATABASE INITIALIZATION
-#
-
-# create the two default users
-user = db.getclass('user')
-user.create(username="admin", password=adminpw,
-    address=admin_email, roles='Admin')
-user.create(username="anonymous", roles='Anonymous')
-
-# add any additional database creation steps here - but only if you
-# haven't initialised the database with the admin "initialise" command
-
-# vim: set et sts=4 sw=4 :
diff --git a/templates/minimal/schema.py b/templates/minimal/schema.py
deleted file mode 100644 (file)
index 909c9b1..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#
-# TRACKER SCHEMA
-#
-
-# Class automatically gets these properties:
-#   creation = Date()
-#   activity = Date()
-#   creator = Link('user')
-#   actor = Link('user')
-
-# The "Minimal" template gets only one class, the required "user"
-# class. That's it. And even that has the bare minimum of properties.
-
-# Note: roles is a comma-separated string of Role names
-user = Class(db, "user", username=String(), password=Password(),
-    address=String(), alternate_addresses=String(), roles=String())
-user.setkey("username")
-#
-# TRACKER SECURITY SETTINGS
-#
-# See the configuration and customisation document for information
-# about security setup.
-
-#
-# REGULAR USERS
-#
-# Give the regular users access to the web and email interface
-db.security.addPermissionToRole('User', 'Web Access')
-db.security.addPermissionToRole('User', 'Email Access')
-
-# May users view other user information?
-# Comment these lines out if you don't want them to
-db.security.addPermissionToRole('User', 'View', 'user')
-
-# Users should be able to edit their own details -- this permission is
-# limited to only the situation where the Viewed or Edited item is their own.
-def own_record(db, userid, itemid):
-    '''Determine whether the userid matches the item being accessed.'''
-    return userid == itemid
-p = db.security.addPermission(name='View', klass='user', check=own_record,
-    description="User is allowed to view their own user details")
-db.security.addPermissionToRole('User', p)
-p = db.security.addPermission(name='Edit', klass='user', check=own_record,
-    description="User is allowed to edit their own user details")
-db.security.addPermissionToRole('User', p)
-
-#
-# ANONYMOUS USER PERMISSIONS
-#
-# Let anonymous users access the web interface. Note that almost all
-# trackers will need this Permission. The only situation where it's not
-# required is in a tracker that uses an HTTP Basic Authenticated front-end.
-db.security.addPermissionToRole('Anonymous', 'Web Access')
-
-# Let anonymous users access the email interface (note that this implies
-# that they will be registered automatically, hence they will need the
-# "Create" user Permission below)
-db.security.addPermissionToRole('Anonymous', 'Email Access')
-
-# Assign the appropriate permissions to the anonymous user's
-# Anonymous Role. Choices here are:
-# - Allow anonymous users to register
-db.security.addPermissionToRole('Anonymous', 'Create', 'user')
-
-# vim: set et sts=4 sw=4 :