summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 0f4768d)
raw | patch | inline | side by side (parent: 0f4768d)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Thu, 17 Apr 2003 03:38:00 +0000 (03:38 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Thu, 17 Apr 2003 03:38:00 +0000 (03:38 +0000) |
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1663 57a73879-2fb5-44c3-a270-3262357dd7e2
110 files changed:
diff --git a/CHANGES.txt b/CHANGES.txt
index fc64ee6f619fbac1776204863a1aaa613bbbf917..900ea99880ef891b7041dd4255dcb9668b4d1dae 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
- added command-line functionality for roundup-adming (sf feature 687664)
- added nicer popup windows for topic, nosy, etc (has add/remove buttons)
thanks Gus Gollings
+- HTML templating files now have a .html extension
+- Roundup templates are now distributed much more sanely, allowing for
+ 3rd-party templates.
Fixed:
diff --git a/MANIFEST.in b/MANIFEST.in
index a0cbe8119d8eed5c57c99c1e11644204d610b968..26aa1a6cdf5c21f40b58006d210976ca5ade809b 100644 (file)
--- a/MANIFEST.in
+++ b/MANIFEST.in
-recursive-include roundup *.* home* page*
+recursive-include roundup *.*
recursive-include frontends *.*
recursive-include scripts *.* *-*
recursive-include tools *.*
recursive-include test *.py *.txt
recursive-include doc *.html *.png *.txt *.css *.1
recursive-include detectors *.py
+recursive-include templates *.* home* page*
recursive-exclude roundup *.pyc *.pyo .cvsignore
recursive-exclude frontends *.pyc *.pyo .cvsignore
+recursive-exclude templates *.pyc *.pyo .cvsignore
include run_tests *.txt
exclude BUILD.txt I18N_PROGRESS.txt TODO.txt
exclude doc/security.txt doc/templating.txt
diff --git a/roundup/admin.py b/roundup/admin.py
index 65bfa8c213535de51e3e8b39954a9bbb562fe78c..fda6e461e9639348cc729543d8cbace41f4c2be9 100644 (file)
--- a/roundup/admin.py
+++ b/roundup/admin.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: admin.py,v 1.50 2003-03-27 05:23:39 richard Exp $
+# $Id: admin.py,v 1.51 2003-04-17 03:37:57 richard Exp $
'''Administration commands for maintaining Roundup trackers.
'''
-import sys, os, getpass, getopt, re, UserDict, shlex, shutil
+import sys, os, getpass, getopt, re, UserDict, shlex, shutil, rfc822
try:
import csv
except ImportError:
print line
return 0
+ def listTemplates(self):
+ ''' List all the available templates.
+
+ Look in three places:
+ <prefix>/share/roundup/templates
+ <__file__>/../templates
+ current dir
+ '''
+ # OK, try <prefix>/share/roundup/templates
+ # -- this module (roundup.admin) will be installed in something
+ # _like_ /usr/lib/python2.2/site-packages/roundup/admin.py, and
+ # we're interested in where the "lib" directory is - ie. the /usr/
+ # part
+ path = __file__
+ for i in range(5):
+ path = os.path.dirname(path)
+ tdir = os.path.join(path, 'share', 'roundup', 'templates')
+ if os.path.isdir(tdir):
+ templates = listTemplates(tdir)
+ else:
+ templates = {}
+
+ # OK, now try as if we're in the roundup source distribution
+ # directory, so this module will be in .../roundup-*/roundup/admin.py
+ # and we're interested in the .../roundup-*/ part.
+ path = __file__
+ for i in range(2):
+ path = os.path.dirname(path)
+ tdir = os.path.join(path, 'templates')
+ if os.path.isdir(tdir):
+ templates.update(listTemplates(tdir))
+
+ return templates
+
def help_initopts(self):
- import roundup.templates
- templates = roundup.templates.listTemplates()
- print _('Templates:'), ', '.join(templates)
+ templates = self.listTemplates()
+ print _('Templates:'), ', '.join(templates.keys())
import roundup.backends
backends = roundup.backends.__all__
print _('Back ends:'), ', '.join(backends)
' does not exist')%locals()
# select template
- import roundup.templates
- templates = roundup.templates.listTemplates()
+ templates = self.listTemplates()
template = len(args) > 1 and args[1] or ''
- if template not in templates:
- print _('Templates:'), ', '.join(templates)
- while template not in templates:
+ if not templates.has_key(template):
+ print _('Templates:'), ', '.join(templates.keys())
+ while not templates.has_key(template):
template = raw_input(_('Select template [classic]: ')).strip()
if not template:
template = 'classic'
# XXX perform a unit test based on the user's selections
# install!
- init.install(tracker_home, template)
+ init.install(tracker_home, templates[template]['path'])
init.write_select_db(tracker_home, backend)
print _('''
if self.db:
self.db.close()
+
+def listTemplates(dir):
+ ''' List all the Roundup template directories in a given directory.
+
+ Find all the dirs that contain a TEMPLATE-INFO.txt and parse it.
+
+ Return a list of dicts of info about the templates.
+ '''
+ ret = {}
+ for idir in os.listdir(dir):
+ idir = os.path.join(dir, idir)
+ ti = os.path.join(idir, 'TEMPLATE-INFO.txt')
+ if os.path.isfile(ti):
+ m = rfc822.Message(open(ti))
+ ti = {}
+ ti['name'] = m['name']
+ ti['description'] = m['description']
+ ti['intended-for'] = m['intended-for']
+ ti['path'] = idir
+ ret[m['name']] = ti
+ return ret
+
if __name__ == '__main__':
tool = AdminTool()
sys.exit(tool.main())
index e2d2b6c52c260be8309db61875730f420d6b74ce..4eacc8cc258846563f534b4a455cc4345ff074fe 100644 (file)
if os.path.isdir(filename): continue
if '.' in filename:
name, extension = filename.split('.')
- self.getTemplate(name, extension)
+ self.get(name, extension)
else:
- self.getTemplate(filename, None)
+ self.get(filename, None)
def get(self, name, extension=None):
''' Interface to get a template, possibly loading a compiled template.
filename = name
src = os.path.join(self.dir, filename)
+ if not os.path.exists(src):
+ filename = filename + '.html'
+ src = os.path.join(self.dir, filename)
+ if not os.path.exists(src):
+ if not extension:
+ raise NoTemplate, 'Template file "%s" doesn\'t exist'%name
+
+ # try for a generic template
+ generic = '_generic.%s'%extension
+ src = os.path.join(self.dir, generic)
+ if not os.path.exists(src):
+ generic = '_generic.%s.html'%extension
+ src = os.path.join(self.dir, generic)
+ if not os.path.exists(src):
+ raise NoTemplate, 'No template file exists for '\
+ 'templating "%s" with template "%s" (neither '\
+ '"%s" nor "%s")'%(name, extension, filename,
+ generic)
+ filename = generic
+
try:
stime = os.stat(src)[os.path.stat.ST_MTIME]
except os.error, error:
if error.errno != errno.ENOENT:
raise
- if not extension:
- raise NoTemplate, 'Template file "%s" doesn\'t exist'%name
-
- # try for a generic template
- generic = '_generic.%s'%extension
- src = os.path.join(self.dir, generic)
- try:
- stime = os.stat(src)[os.path.stat.ST_MTIME]
- except os.error, error:
- if error.errno != errno.ENOENT:
- raise
- # nicer error
- raise NoTemplate, 'No template file exists for templating '\
- '"%s" with template "%s" (neither "%s" nor "%s")'%(name,
- extension, filename, generic)
- filename = generic
if self.templates.has_key(src) and \
stime < self.templates[src].mtime:
diff --git a/roundup/init.py b/roundup/init.py
index 9a7ffc51241d5c8bb94459809671d1963bee99fe..fd7124c79460d28de6509dd723440826a4b8a684 100644 (file)
--- a/roundup/init.py
+++ b/roundup/init.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: init.py,v 1.25 2003-02-25 10:19:31 richard Exp $
+# $Id: init.py,v 1.26 2003-04-17 03:37:58 richard Exp $
__doc__ = """
Init (create) a roundup instance.
'''Install an instance using the named template and backend.
instance_home - the directory to place the instance data in
- template - the template to use in creating the instance data
- backend - the database to use to store the instance data
+ template - the directory holding the template to use in creating
+ the instance data
The instance_home directory will be created using the files found in
the named template (roundup.templates.<name>). A standard instance_home
. detectors/
- the auditor and reactor modules for this instance
- The html directory is typically extracted from the htmlbase module in
- the template.
'''
- # first, copy the template dir over
- from roundup.templates import builder
-
- # copy the roundup.templates.<template> package contents to the instance dir
- template_dir = os.path.split(__file__)[0]
- template_name = template
- template = os.path.join(template_dir, 'templates', template)
+ # At the moment, it's just a copy
copytree(template, instance_home)
- builder.installHtmlBase(template_name, instance_home)
-
def write_select_db(instance_home, backend):
''' Write the file that selects the backend for the tracker
diff --git a/roundup/mailgw.py b/roundup/mailgw.py
index 468a3b7f2f25cfbd2add7fdf6d4325da176da930..1a5332bb99027c4fed6a2378da084d617b205e0e 100644 (file)
--- a/roundup/mailgw.py
+++ b/roundup/mailgw.py
an exception, the original message is bounced back to the sender with the
explanatory message given in the exception.
-$Id: mailgw.py,v 1.114 2003-04-10 05:12:41 richard Exp $
+$Id: mailgw.py,v 1.115 2003-04-17 03:37:59 richard Exp $
'''
import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
# parse the body of the message, stripping out bits as appropriate
summary, content = parseContent(content, keep_citations,
keep_body)
+ content = content.strip()
#
# handle the attachments
diff --git a/roundup/templates/.cvsignore b/roundup/templates/.cvsignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*.pyc
-*.pyo
-*.cover
-*_htmlbase.py
-*_htmlbase.pyc
diff --git a/roundup/templates/README.txt b/roundup/templates/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This directory contains "templates" for installations of roundup.
-
-Choose a template that matches your needs most closely, then run
-roundup-admin init <templatename>, then customise the new instance's
-templates.
-
-The currently available templates are:
-
- classic -- The schema is as described in the Roundup spec.
-
- extended -- The classic schema with some extra fields useful for support
- calls: product identification, customer name, source of call,
- log of time spent on call.
-
diff --git a/roundup/templates/__init__.py b/roundup/templates/__init__.py
+++ /dev/null
@@ -1,32 +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: __init__.py,v 1.5 2002-09-10 01:07:06 richard Exp $
-
-import os
-
-def listTemplates():
- t_dir = os.path.split(__file__)[0]
- l = []
- for entry in os.listdir(t_dir):
- # this isn't strictly necessary - the CVS dir won't be distributed
- if entry == 'CVS': continue
- if os.path.isdir(os.path.join(t_dir, entry)):
- l.append(entry)
- return l
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/builder.py b/roundup/templates/builder.py
+++ /dev/null
@@ -1,92 +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: builder.py,v 1.4 2002-09-13 04:39:12 richard Exp $
-import os, sys, glob, errno, re
-
-__doc__ = """
-Collect template parts and create instance template files.
-"""
-
-preamble = """
-# Do Not Edit (Unless You Want To)
-# This file automagically generated by roundup.templatebuilder.makeHtmlBase
-#
-"""
-
-def makeHtmlBase(templateDir):
- ''' make a <template>_htmlbase.py file in rondup.tempaltes, from the
- contents of templateDir/html
- '''
- print "packing up templates in", templateDir
-
- filelist = glob.glob(os.path.join(templateDir, 'html', '*'))
- filelist = filter(os.path.isfile, filelist) # only want files
- filelist.sort()
-
- # ok, figure the template name and templates dir
- dir, name = os.path.split(templateDir)
-
- fd = open(os.path.join(dir, '%s_htmlbase.py'%name), 'w')
- fd.write(preamble)
- for file in filelist:
- # skip the backup files created by richard's vim
- if file[-1] == '~': continue
- mangled_name = os.path.basename(file).replace('.','DOT')
- fd.write('%s = """'%mangled_name)
- fd.write(re.sub(r'\$((Id|File|Log).*?)\$', r'dollar\1dollar',
- open(file).read(), re.I))
- fd.write('"""\n\n')
- fd.close()
-
-def installHtmlBase(template, installDir):
- ''' passed a template name and an installDir, unpacks the html files into
- the installdir
- '''
- tmod = '%s_htmlbase'%template
- tdir = __import__('roundup.templates.'+tmod).templates
- if hasattr(tdir, tmod):
- htmlbase = getattr(tdir, tmod)
- else:
- raise "TemplateError", \
- "couldn't find roundup.templates.%s_htmlbase"%template
- installDir = os.path.join(installDir, 'html')
- try:
- os.makedirs(installDir)
- except OSError, error:
- if error.errno != errno.EEXIST: raise
-
-# print "installing from", htmlbase.__file__, "into", installDir
- modulecontents = dir(htmlbase)
- for mangledfile in modulecontents:
- if mangledfile.startswith('__') and mangledfile.endswith('__'):
- continue
- filename = re.sub('DOT', '.', mangledfile)
- outfile = os.path.join(installDir, filename)
- outfd = open(outfile, 'w')
- data = getattr(htmlbase, mangledfile)
- outfd.write(data)
-
-if __name__ == "__main__":
- if len(sys.argv) == 2:
- makeHtmlBase(sys.argv[1])
- elif len(sys.argv) == 3:
- installHtmlBase(sys.argv[1], sys.argv[2])
- else:
- print "Usage: %s <template directory>"%sys.argv[0]
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/classic/.cvsignore b/roundup/templates/classic/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*.pyc
-*.pyo
-htmlbase.py
-*.cover
diff --git a/roundup/templates/classic/__init__.py b/roundup/templates/classic/__init__.py
+++ /dev/null
@@ -1,24 +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: __init__.py,v 1.7 2002-09-09 23:55:19 richard Exp $
-
-import config
-from dbinit import open, init
-from interfaces import Client, MailGW
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/classic/config.py b/roundup/templates/classic/config.py
+++ /dev/null
@@ -1,100 +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: config.py,v 1.7 2003-01-12 00:41:27 richard Exp $
-
-import os
-
-# roundup home is this package's directory
-TRACKER_HOME=os.path.split(__file__)[0]
-
-# The SMTP mail host that roundup will use to send mail
-MAILHOST = 'localhost'
-
-# The domain name used for email addresses.
-MAIL_DOMAIN = 'your.tracker.email.domain.example'
-
-# This is the directory that the database is going to be stored in
-DATABASE = os.path.join(TRACKER_HOME, 'db')
-
-# This is the directory that the HTML templates reside in
-TEMPLATES = os.path.join(TRACKER_HOME, 'html')
-
-# A descriptive name for your roundup instance
-TRACKER_NAME = 'Roundup issue tracker'
-
-# The email address that mail to roundup should go to
-TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
-
-# The web address that the tracker is viewable at. This will be included in
-# information sent to users of the tracker. The URL MUST include the cgi-bin
-# part or anything else that is required to get to the home page of the
-# tracker. You MUST include a trailing '/' in the URL.
-TRACKER_WEB = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/'
-
-# The email address that roundup will complain to if it runs into trouble
-ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
-
-# Additional text to include in the "name" part of the From: address used
-# in nosy messages. If the sending user is "Foo Bar", the From: line is
-# usually:
-# "Foo Bar" <issue_tracker@tracker.example>
-# the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
-# "Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>
-EMAIL_FROM_TAG = ""
-
-# Send nosy messages to the author of the message
-MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no'
-
-# Does the author of a message get placed on the nosy list automatically?
-# If 'new' is used, then the author will only be added when a message
-# creates a new issue. If 'yes', then the author will be added on followups
-# too. If 'no', they're never added to the nosy.
-ADD_AUTHOR_TO_NOSY = 'new' # one of 'yes', 'no', 'new'
-
-# Do the recipients (To:, Cc:) of a message get placed on the nosy list?
-# If 'new' is used, then the recipients will only be added when a message
-# creates a new issue. If 'yes', then the recipients will be added on followups
-# too. If 'no', they're never added to the nosy.
-ADD_RECIPIENTS_TO_NOSY = 'new' # either 'yes', 'no', 'new'
-
-# Where to place the email signature
-EMAIL_SIGNATURE_POSITION = 'bottom' # one of 'top', 'bottom', 'none'
-
-# Keep email citations when accepting messages. Setting this to "no" strips
-# out "quoted" text from the message. Signatures are also stripped.
-EMAIL_KEEP_QUOTED_TEXT = 'yes' # either 'yes' or 'no'
-
-# Preserve the email body as is - that is, keep the citations _and_
-# signatures.
-EMAIL_LEAVE_BODY_UNCHANGED = 'no' # either 'yes' or 'no'
-
-# Default class to use in the mailgw if one isn't supplied in email
-# subjects. To disable, comment out the variable below or leave it blank.
-# Examples:
-MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default
-#MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out)
-
-#
-# SECURITY DEFINITIONS
-#
-# define the Roles that a user gets when they register with the tracker
-# these are a comma-separated string of role names (e.g. 'Admin,User')
-NEW_WEB_USER_ROLES = 'User'
-NEW_EMAIL_USER_ROLES = 'User'
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/classic/dbinit.py b/roundup/templates/classic/dbinit.py
+++ /dev/null
@@ -1,203 +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: dbinit.py,v 1.34 2003-04-10 05:12:42 richard Exp $
-
-import os
-
-import config
-from select_db import Database, Class, FileClass, IssueClass
-
-def open(name=None):
- ''' as from the roundupdb method openDB
- '''
- from roundup.hyperdb import String, Password, Date, Link, Multilink
- from roundup.hyperdb import Interval, Boolean, Number
-
- # open the database
- db = Database(config, name)
-
- #
- # Now initialise the schema. Must do this each time the database is
- # opened.
- #
-
- # Class automatically gets these properties:
- # creation = Date()
- # activity = Date()
- # creator = Link('user')
- pri = Class(db, "priority",
- name=String(), order=String())
- pri.setkey("name")
-
- stat = Class(db, "status",
- name=String(), order=String())
- stat.setkey("name")
-
- keyword = Class(db, "keyword",
- name=String())
- keyword.setkey("name")
-
- query = Class(db, "query",
- klass=String(), name=String(),
- url=String())
- query.setkey("name")
-
- # add any additional database schema configuration here
-
- # Note: roles is a comma-separated string of Role names
- user = Class(db, "user",
- username=String(), password=Password(),
- address=String(), realname=String(),
- phone=String(), organisation=String(),
- alternate_addresses=String(),
- queries=Multilink('query'), roles=String(),
- timezone=String())
- user.setkey("username")
-
- # FileClass automatically gets these properties:
- # content = String() [saved to disk in <tracker home>/db/files/]
- # (it also gets the Class properties creation, activity and creator)
- 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(), type=String())
-
- # IssueClass automatically gets these properties:
- # title = String()
- # messages = Multilink("msg")
- # files = Multilink("file")
- # nosy = Multilink("user")
- # superseder = Multilink("issue")
- # (it also gets the Class properties creation, activity and creator)
- issue = IssueClass(db, "issue",
- assignedto=Link("user"), topic=Multilink("keyword"),
- priority=Link("priority"), status=Link("status"))
-
- #
- # SECURITY SETTINGS
- #
- # See the configuration and customisation document for information
- # about security setup.
- # Add new Permissions for this schema
- for cl in 'issue', 'file', 'msg', 'user', 'query', 'keyword':
- db.security.addPermission(name="Edit", klass=cl,
- description="User is allowed to edit "+cl)
- db.security.addPermission(name="View", klass=cl,
- description="User is allowed to access "+cl)
-
- # Assign the access and edit Permissions for issue, file and message
- # to regular users now
- for cl in 'issue', 'file', 'msg', 'query', 'keyword':
- p = db.security.getPermission('View', cl)
- db.security.addPermissionToRole('User', p)
- p = db.security.getPermission('Edit', cl)
- db.security.addPermissionToRole('User', p)
-
- # and give the regular users access to the web and email interface
- p = db.security.getPermission('Web Access')
- db.security.addPermissionToRole('User', p)
- p = db.security.getPermission('Email Access')
- db.security.addPermissionToRole('User', p)
-
- # May users view other user information? Comment these lines out
- # if you don't want them to
- p = db.security.getPermission('View', 'user')
- db.security.addPermissionToRole('User', p)
-
- # Assign the appropriate permissions to the anonymous user's Anonymous
- # Role. Choices here are:
- # - Allow anonymous users to register through the web
- p = db.security.getPermission('Web Registration')
- db.security.addPermissionToRole('Anonymous', p)
- # - Allow anonymous (new) users to register through the email gateway
- p = db.security.getPermission('Email Registration')
- db.security.addPermissionToRole('Anonymous', p)
- # - Allow anonymous users access to the "issue" class of data
- # Note: this also grants access to related information like files,
- # messages, statuses etc that are linked to issues
- p = db.security.getPermission('View', 'issue')
- db.security.addPermissionToRole('Anonymous', p)
- # - Allow anonymous users access to edit the "issue" class of data
- # Note: this also grants access to create related information like
- # files and messages etc that are linked to issues
- #p = db.security.getPermission('Edit', 'issue')
- #db.security.addPermissionToRole('Anonymous', p)
-
- # oh, g'wan, let anonymous access the web interface too
- p = db.security.getPermission('Web Access')
- db.security.addPermissionToRole('Anonymous', p)
-
- import detectors
- detectors.init(db)
-
- # schema is set up - run any post-initialisation
- db.post_init()
- return db
-
-def init(adminpw):
- ''' as from the roundupdb method initDB
-
- Open the new database, and add new nodes - used for initialisation. You
- can edit this before running the "roundup-admin initialise" command to
- change the initial database entries.
- '''
- dbdir = os.path.join(config.DATABASE, 'files')
- if not os.path.isdir(dbdir):
- os.makedirs(dbdir)
-
- db = open("admin")
- db.clear()
-
- #
- # 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=config.ADMIN_EMAIL, roles='Admin')
- user.create(username="anonymous", roles='Anonymous')
-
- # add any additional database create steps here - but only if you
- # haven't initialised the database with the admin "initialise" command
-
- db.commit()
-
-# vim: set filetype=python ts=4 sw=4 et si
-
diff --git a/roundup/templates/classic/detectors/.cvsignore b/roundup/templates/classic/detectors/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.pyc
-*.pyo
-*.cover
diff --git a/roundup/templates/classic/detectors/__init__.py b/roundup/templates/classic/detectors/__init__.py
+++ /dev/null
@@ -1,36 +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: __init__.py,v 1.8 2003-02-24 04:12:15 richard Exp $
-
-import sys, os, imp
-
-def init(db):
- ''' execute the init functions of all the modules in this directory
- '''
- this_dir = os.path.split(__file__)[0]
- for file in os.listdir(this_dir):
- path = os.path.join(this_dir, file)
- name, ext = os.path.splitext(file)
- if name == '__init__':
- continue
- if ext == '.py':
- module = imp.load_module(name, open(path), file,
- ('.py', 'r', imp.PY_SOURCE))
- module.init(db)
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/classic/detectors/messagesummary.py b/roundup/templates/classic/detectors/messagesummary.py
+++ /dev/null
@@ -1,19 +0,0 @@
-#$Id: messagesummary.py,v 1.1 2003-02-13 21:14:27 richard 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'], 1, 1)
- 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/roundup/templates/classic/detectors/nosyreaction.py b/roundup/templates/classic/detectors/nosyreaction.py
+++ /dev/null
@@ -1,142 +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.14 2002-09-10 01:07:06 richard Exp $
-
-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 = {}
- 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:
- if not current.has_key(value):
- current[value] = 1
-
- # 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
- if not current.has_key(value):
- current[value] = 1
-
- # 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:
- if not current.has_key(assignedto_id):
- current[assignedto_id] = 1
-
- # 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
- # there before - make sure we don't get a cached version!
- oldmessages = cl.get(nodeid, 'messages', cache=0)
- 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')
- current[authid] = 1
-
- # add on the recipients of the message
- if add_recips in ok:
- for recipient in msg.get(msgid, 'recipients'):
- current[recipient] = 1
-
- # that's it, save off the new nosy list
- newvalues['nosy'] = current.keys()
-
-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/roundup/templates/classic/detectors/statusauditor.py b/roundup/templates/classic/detectors/statusauditor.py
+++ /dev/null
@@ -1,78 +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.3 2002-10-11 01:26:05 richard Exp $
-
-def chatty(db, cl, nodeid, newvalues):
- ''' If the issue is currently 'unread', 'resolved' or 'done-cbb', 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', cache=0):
- 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') and newvalues['status'] != current_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:
- # 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
-
- # ok, do it
- newvalues['status'] = db.status.lookup('unread')
-
-
-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/roundup/templates/classic/html/_generic.help b/roundup/templates/classic/html/_generic.help
+++ /dev/null
@@ -1,91 +0,0 @@
-<html>
-<head>
-<link rel="stylesheet" type="text/css" href="_file/style.css">
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
-<script language="JavaScript"
- tal:condition="python:request.form.has_key('property')"
- tal:content="structure string:
-
-// this is the name of the field in the original form that we're working on
-field = '${request/form/property/value}';
-
-function listClose() {
- window.close();
-}
-
-function listClear() {
- window.opener.document.itemSynopsis[field].value = '';
-}
-
-function pick(opt) {
- if (window.opener && !window.opener.closed) {
- window.opener.document.itemSynopsis[field].value = opt;
- }
-}
-
-// add a value to the form field
-function add(opt) {
- val = window.opener.document.itemSynopsis[field].value;
- if (/^\s*$$/.test(val)) {
- newval = opt; // existing is all whitespace, so just replace
- } else {
- newval = val + ', ' + opt;
- }
- pick(newval);
-}
-
-// remove a value from the form field
-function remove(opt) {
- // ((opt(,\s*)?)|(,\s*opt))
- replaceStr = new String('(('+opt+'(,\\s*)?)|(,\\s*'+opt+'))');
- re = new RegExp(replaceStr);
-
- str = window.opener.document.itemSynopsis[field].value;
-
- // replace occurences with empty string
- newstr = str.replace(re, '');
- pick(newstr);
-}
-">
-</script>
-</head>
-
-<body class="body" marginwidth="0" marginheight="0">
-<form>
-<div style="padding:10px;text-align:center;">
- <script language="javascript">
- // put up a 'reset' button if the field has values when we pop up this window
-
- // this is the name of the field in the original form that we're working on
- orig = window.opener.document.itemSynopsis[field].value;
- if (/[^\s]/.test(orig)) {
- reset = '<input type="button" onclick="pick(orig);" ' +
- 'value="Reset to original values" /> | ';
- document.write(reset);
- }
- </script>
- <input type="button"
- tal:attributes="value string:Clear all ${request/form/property/value} values"
- onclick="listClear();" /> |
- <input type="button" onclick="listClose();" value="Close this window" />
-</div>
-
-<table class="classhelp"
- tal:define="props python:request.form['properties'].value.split(',')">
-<tr>
- <th tal:condition="python:request.form.has_key('property')">add/remove</th>
- <th tal:repeat="prop props" tal:content="prop"></th>
-</tr>
-<tr tal:repeat="item context/list">
- <td tal:condition="python:request.form.has_key('property')">
- <input type="button" tal:define="opt python: item[props[0]]"
- tal:attributes="onclick string:add('${opt}')" value=" + ">
- <input type="button" tal:define="opt python: item[props[0]]"
- tal:attributes="onclick string:remove('${opt}')" value=" - " />
- </td>
- <td tal:repeat="prop props" tal:content="structure python:item[prop]"></td>
-</tr>
-</table>
-</form>
-</body>
-</html>
diff --git a/roundup/templates/classic/html/_generic.index b/roundup/templates/classic/html/_generic.index
+++ /dev/null
@@ -1,48 +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"
- tal:content="python:context._classname.capitalize()+' editing'"></title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<tal:block tal:condition="context/is_edit_ok">
-<p class="form-help">
- You may edit the contents of the <span tal:replace="request/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>
-
-<form onSubmit="return submit_once()" method="POST">
-<textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea>
-<br>
-<input type="hidden" name=":action" value="editCSV">
-<input type="submit" value="Edit Items">
-</form>
-</tal:block>
-
-<tal:block tal:condition="context/is_only_view_ok">
-view ok
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/_generic.item b/roundup/templates/classic/html/_generic.item
+++ /dev/null
@@ -1,56 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title"
- tal:content="python:context._classname.capitalize()+' editing'"></title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<input type="hidden" name=":template" value="item">
-<input type="hidden" name=":required" value="title">
-
-<table class="form">
-
-<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>
-<tr>
- <td> </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/roundup/templates/classic/html/file.index b/roundup/templates/classic/html/file.index
+++ /dev/null
@@ -1,30 +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">
- <span tal:replace="config/TRACKER_NAME" />: List of files
-</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>List of files</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<table class="otherinfo">
-<tr><th style="padding-right: 10">Download</th>
- <th style="padding-right: 10">Content Type</th>
- <th style="padding-right: 10">Uploaded By</th>
- <th style="padding-right: 10">Date</th>
-</tr>
-<tr tal:repeat="file context/list">
- <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>
-</table>
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/file.item b/roundup/templates/classic/html/file.item
+++ /dev/null
@@ -1,58 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">File display</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>File display</h2>
-</td>
-
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<input type="hidden" name=":template" value="item">
-<input type="hidden" name=":required" value="name,type">
-
-<input type="hidden" name=":multilink"
- tal:condition="python:request.form.has_key(':multilink')"
- tal:attributes="value request/form/:multilink/value">
-
-<table class="form">
- <tr>
- <th>Name</th>
- <td tal:content="structure context/name/field"></td>
- </tr>
- <tr>
- <th>Content Type</th>
- <td tal:content="structure context/type/field"></td>
- </tr>
-
- <tr>
- <td> </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}">download</a>
-
-<table class="form" tal:condition="context/is_only_view_ok">
- <tr>
- <th>Name</th>
- <td tal:content="context/name"></td>
- </tr>
- <tr>
- <th>Content Type</th>
- <td tal:content="context/type"></td>
- </tr>
-</table>
-
-<tal:block tal:condition="python:context.id and context.is_view_ok()"
- tal:replace="structure context/history" />
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/home b/roundup/templates/classic/html/home
+++ /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/roundup/templates/classic/html/home.classlist b/roundup/templates/classic/html/home.classlist
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">List of classes</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>List of classes</h2>
-</td>
-<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/roundup/templates/classic/html/issue.index b/roundup/templates/classic/html/issue.index
+++ /dev/null
@@ -1,111 +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">
- <span tal:replace="config/TRACKER_NAME" />: List of issues
-</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>List of issues</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<tal:block tal:condition="not:context/is_view_ok">
-You are not allowed to view this page.
-</tal:block>
-
-<tal:block tal:define="batch request/batch" tal:condition="context/is_view_ok">
- <table class="list">
- <tr>
- <th tal:condition="request/show/priority">Priority</th>
- <th tal:condition="request/show/id">ID</th>
- <th tal:condition="request/show/creation">Creation</th>
- <th tal:condition="request/show/activity">Activity</th>
- <th tal:condition="request/show/topic">Topic</th>
- <th tal:condition="request/show/title">Title</th>
- <th tal:condition="request/show/status">Status</th>
- <th tal:condition="request/show/creator">Created By</th>
- <th tal:condition="request/show/assignedto">Assigned To</th>
- </tr>
- <tal:block tal:repeat="i batch">
- <tr tal:condition="python:request.group[1] and
- batch.propchanged(request.group[1])">
- <th tal:attributes="colspan python:len(request.columns)"
- tal:content="python:i[request.group[1]]" class="group">
- </th>
- </tr>
- <tr tal:attributes="class python:['normal', 'alt'][repeat['i'].index%6/3]">
- <td tal:condition="request/show/priority" tal:content="i/priority"></td>
- <td tal:condition="request/show/id" tal:content="i/id"></td>
- <td nowrap tal:condition="request/show/creation"
- tal:content="i/creation/reldate"></td>
- <td nowrap tal:condition="request/show/activity"
- tal:content="i/activity/reldate"></td>
- <td tal:condition="request/show/topic" tal:content="i/topic"></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" tal:content="i/status"></td>
- <td tal:condition="request/show/creator" tal:content="i/creator"></td>
- <td tal:condition="request/show/assignedto" tal:content="i/assignedto"></td>
- </tr>
- </tal:block>
- <tr class="navigation" tal:define="colspan python:len(request.columns)">
- <th tal:attributes="colspan python:colspan/2">
- <a tal:define="prev batch/previous" tal:condition="prev"
- tal:attributes="href python:request.indexargs_url(request.classname,
- {':startwith':prev.first, ':pagesize':prev.size})"><< previous</a>
-
- </th>
- <th tal:attributes="colspan python:colspan/2 + colspan%2">
- <a tal:define="next batch/next" tal:condition="next"
- tal:attributes="href python:request.indexargs_url(request.classname,
- {':startwith':next.first, ':pagesize':next.size})">next >></a>
-
- </th>
- </tr>
-</table>
-
-<form method="GET" tal:attributes="action request/classname">
- <tal:block tal:replace="structure python:request.indexargs_form(sort=0, group=0)" />
- <table class="form">
- <tr tal:condition="batch">
- <th>Sort on:</th>
- <td>
- <select name=":sort">
- <option value="">- nothing -</option>
- <option tal:repeat="col context/properties"
- tal:attributes="value col/_name;
- selected python:col._name == request.sort[1]"
- tal:content="col/_name">column</option>
- </select>
- </td>
- <th>Descending:</th>
- <td><input type="checkbox" name=":sortdir"
- tal:attributes="checked python:request.sort[0] == '-'">
- </td>
- </tr>
- <tr>
- <th>Group on:</th>
- <td>
- <select name=":group">
- <option value="">- nothing -</option>
- <option tal:repeat="col context/properties"
- tal:attributes="value col/_name;
- selected python:col._name == request.group[1]"
- tal:content="col/_name">column</option>
- </select>
- </td>
- <th>Descending:</th>
- <td><input type="checkbox" name=":groupdir"
- tal:attributes="checked python:request.group[0] == '-'">
- </td>
- </tr>
- <tr><td colspan="4"><input type="submit" value="Redisplay"></td></tr>
- </table>
-</form>
-
-</tal:block>
-
-</td>
-</tal:block>
-
diff --git a/roundup/templates/classic/html/issue.item b/roundup/templates/classic/html/issue.item
+++ /dev/null
@@ -1,174 +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">
-<span tal:replace="config/TRACKER_NAME" />:
-<span tal:condition="context/id"
- tal:replace="string:Issue ${context/id}: ${context/title}" />
-<tal:x tal:condition="not:context/id">New Issue</tal:x>
-</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>
- Issue<span tal:replace="context/id" />
- <tal:x tal:condition="context/is_edit_ok">Editing</tal:x>
- </h2>
-</td>
-
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<form method="POST" name="itemSynopsis" onSubmit="return submit_once()"
- enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<input type="hidden" name=":template" value="item">
-<input type="hidden" name=":required" value="title,priority">
-
-<table class="form">
-<tr>
- <th class="required" nowrap>Title</th>
- <td colspan=3 tal:content="structure python:context.title.field(size=60)">title</td>
-</tr>
-
-<tr>
- <th class="required" nowrap>Priority</th>
- <td tal:content="structure context/priority/menu">priority</td>
- <th nowrap>Status</th>
- <td tal:content="structure context/status/menu">status</td>
-</tr>
-
-<tr>
- <th nowrap>Superseder</th>
- <td>
- <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
- <span tal:replace="structure python:db.issue.classhelp('id,title', property='superseder')" />
- <span tal:condition="context/superseder" tal:repeat="sup context/superseder">
- <br>View: <a tal:attributes="href string:issue${sup/id}"
- tal:content="sup/id"></a>
- </span>
- </td>
- <th nowrap>Nosy List</th>
- <td>
- <span tal:replace="structure context/nosy/field" />
- <span tal:replace="structure
-python:db.user.classhelp('username,realname,address', property='nosy', width='600')" /><br>
- </td>
-</tr>
-
-<tr>
- <th nowrap>Assigned To</th>
- <td tal:content="structure context/assignedto/menu">assignedto menu</td>
- <th nowrap>Topics</th>
- <td>
- <span tal:replace="structure context/topic/field" />
- <span tal:replace="structure python:db.keyword.classhelp(property='topic')" />
- </td>
-</tr>
-
-<tr>
- <th nowrap>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>
- <th nowrap>File</th>
- <td colspan=3><input type="file" name=":file" size="40"></td>
-</tr>
-
-<tr>
- <td> </td>
- <td colspan=3 tal:content="structure context/submit">
- submit button will go here
- </td>
-</tr>
-</table>
-</form>
-
-<table class="form" tal:condition="not:context/id">
-<tr>
- <td>Note: </td>
- <th class="required">highlighted</th>
- <td> fields are required.</td>
-</tr>
-</table>
-
-<table class="form" tal:condition="context/is_only_view_ok">
-<tr>
- <th nowrap>Title</th><td colspan=3 tal:content="context/title">title</td>
-</tr>
-
-<tr>
- <th nowrap>Priority</th><td tal:content="context/priority">priority</td>
- <th nowrap>Status</th><td tal:content="context/status">status</td>
-</tr>
-
-<tr>
- <th nowrap>Superseder</th>
- <td>
- <span tal:condition="context/superseder" tal:repeat="sup context/superseder">
- <br>View: <a tal:attributes="href string:issue${sup/id}"
- tal:content="sup/id"></a>
- </span>
- </td>
- <th nowrap>Nosy List</th><td><span tal:replace="context/nosy" /></td>
-</tr>
-
-<tr>
- <th nowrap>Assigned To</th><td tal:content="context/assignedto"></td>
- <th nowrap>Topics</th><td tal:content="structure context/topic"></td>
-</tr>
-</table>
-
-<tal:block tal:condition="python:context.id and context.is_view_ok()">
-
- <p tal:content="structure string:Created on
- <b>${context/creation}</b> by <b>${context/creator}</b>, last
- changed <b>${context/activity}</b>.">activity info
- </p>
-
- <table class="messages" tal:condition="context/messages">
- <tr><th colspan="4" class="header">Messages</th></tr>
- <tal:block tal:repeat="msg context/messages/reverse">
- <tr>
- <th><a tal:attributes="href string:msg${msg/id}"
- tal:content="string:msg${msg/id}"></a></th>
- <th tal:content="string:Author: ${msg/author}">author</th>
- <th tal:content="string:Date: ${msg/date}">date</th>
- <th>
- <a tal:attributes="href string:?:remove:messages=${msg/id}&:action=edit">remove</a>
- </th>
- </tr>
- <tr>
- <td colspan="4" class="content">
- <pre tal:content="msg/content">content</pre>
- </td>
- </tr>
- </tal:block>
- </table>
-
- <table class="files" tal:condition="context/files">
- <tr><th colspan="2" class="header">Files</th></tr>
- <tr><th>File name</th><th>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" />
-
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/issue.search b/roundup/templates/classic/html/issue.search
+++ /dev/null
@@ -1,192 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">Issue searching</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>Issue searching</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<form method="GET" tal:attributes="action request/classname">
-<input type="hidden" name=":action" value="search">
-
-<table class="form" tal:define="
- cols python:'id activity priority title status assignedto'.split();
- defsort python:['activity'];
- defgroup python:['priority'];
- defdisp python:'id activity title status assignedto'.split()">
-
-<tr>
- <th class="header"> </th>
- <th class="header">Filter on</th>
- <th class="header">Display</th>
- <th class="header">Sort on</th>
- <th class="header">Group on</th>
-</tr>
-
-<tr>
- <th>All text*:</th>
- <td><input name=":search_text"
- tal:attributes="value request/form/:search_text/value | nothing">
- </td>
- <td> </td>
- <td> </td>
- <td> </td>
-</tr>
-
-<tr>
- <th>Title:</th>
- <td><input name="title"></td>
- <td><input type="checkbox" name=":columns" value="title" checked></td>
- <td><input type="radio" name=":sort" value="title"></td>
- <td> </td>
-</tr>
-
-<tr>
- <th>Topic:</th>
- <td>
- <select name="topic">
- <option value="">don't care</option>
- <option value="">------------</option>
- <option tal:repeat="s db/keyword/list" tal:attributes="value s/name"
- tal:content="s/name">topic to filter on</option>
- </select>
- </td>
- <td><input type="checkbox" name=":columns" value="topic" checked></td>
- <td><input type="radio" name=":sort" value="topic"></td>
- <td><input type="radio" name=":group" value="topic"></td>
-</tr>
-
-<tr>
- <th>ID:</th>
- <td><input name="id"></td>
- <td><input type="checkbox" name=":columns" value="id" checked></td>
- <td><input type="radio" name=":sort" value="id"></td>
- <td> </td>
-</tr>
-
-<tr>
- <th>Creation date:</th>
- <td><input name="creation"></td>
- <td><input type="checkbox" name=":columns" value="creation"></td>
- <td><input type="radio" name=":sort" value="creation"></td>
- <td><input type="radio" name=":group" value="creation"></td>
-</tr>
-
-<tr>
- <th>Creator:</th>
- <td>
- <select name="creator">
- <option value="">don't care</option>
- <option tal:attributes="value request/user/id">created by me</option>
- <option value="-1">------------</option>
- <option tal:repeat="s db/user/list" tal:attributes="value s/id"
- tal:content="s/username">user to filter on</option>
- </select>
- </td>
- <td><input type="checkbox" name=":columns" value="creator" checked></td>
- <td><input type="radio" name=":sort" value="creator"></td>
- <td><input type="radio" name=":group" value="creator"></td>
-</tr>
-
-<tr>
- <th>Activity:</th>
- <td><input name="activity"></td>
- <td><input type="checkbox" name=":columns" value="activity" checked></td>
- <td><input type="radio" name=":sort" value="activity"></td>
- <td> </td>
-</tr>
-
-<tr>
- <th>Priority:</th>
- <td>
- <select name="priority">
- <option value="">don't care</option>
- <option value="-1">not selected</option>
- <option value="">------------</option>
- <option tal:repeat="s db/priority/list" tal:attributes="value s/id"
- tal:content="s/name">priority to filter on</option>
- </select>
- </td>
- <td><input type="checkbox" name=":columns" value="priority"></td>
- <td><input type="radio" name=":sort" value="priority"></td>
- <td><input type="radio" name=":group" value="priority"></td>
-</tr>
-
-<tr>
- <th>Status:</th>
- <td>
- <select name="status">
- <option value="">don't care</option>
- <option value="-1,1,2,3,4,5,6,7">not resolved</option>
- <option value="-1">not selected</option>
- <option value="">------------</option>
- <option tal:repeat="s db/status/list" tal:attributes="value s/id"
- tal:content="s/name">status to filter on</option>
- </select>
- </td>
- <td><input type="checkbox" name=":columns" value="status" checked></td>
- <td><input type="radio" name=":sort" value="status"></td>
- <td><input type="radio" name=":group" value="status"></td>
-</tr>
-
-<tr>
- <th>Assigned To:</th>
- <td>
- <select name="assignedto">
- <option value="">don't care</option>
- <option tal:attributes="value request/user/id">assigned to me</option>
- <option value="-1">unassigned</option>
- <option value="">------------</option>
- <option tal:repeat="s db/user/list" tal:attributes="value s/id"
- tal:content="s/username">user to filter on</option>
- </select>
- </td>
- <td><input type="checkbox" name=":columns" value="assignedto" checked></td>
- <td><input type="radio" name=":sort" value="assignedto"></td>
- <td><input type="radio" name=":group" value="assignedto"></td>
-</tr>
-
-<tr>
-<th>Pagesize:</th>
-<td><input type="text" name=":pagesize" size="3" value="50"></td>
-</tr>
-
-<tr>
-<th>Start With:</th>
-<td><input type="text" name=":startwith" size="3" value="0"></td>
-</tr>
-
-<tr>
-<th>Sort Descending:</th>
-<td><input type="checkbox" name=":sortdir" checked>
-</td>
-
-<tr>
-<th>Group Descending:</th>
-<td><input type="checkbox" name=":groupdir">
-</td>
-</tr>
-
-<tr>
-<th>Query name**:</th>
-<td><input name=":queryname"
- tal:attributes="value request/form/:queryname/value | nothing">
-</td>
-</tr>
-
-<tr><td> </td>
-<td><input type="submit" value="Search"></td>
-</tr>
-
-<tr><td> </td>
- <td colspan="4" class="help">
- *: The "all text" field will look in message bodies and issue titles<br>
- **: If you supply a name, the query will be saved off and available as a
- link in the sidebar
- </td>
-</tr>
-</table>
-
-</form>
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/keyword.item b/roundup/templates/classic/html/keyword.item
+++ /dev/null
@@ -1,53 +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">Keyword editing</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>Keyword editing</h2>
-</td>
-<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">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">
- 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">
- 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">
-
- <input type="hidden" name=":required" value="name">
- <input type="hidden" name=":template" value="item">
-
- <table class="form">
- <tr>
- <th nowrap>Keyword</th>
- <td tal:content="structure context/name/field">name</td>
- </tr>
-
- <tr>
- <td> </td>
- <td colspan=3 tal:content="structure context/submit">
- submit button will go here
- </td>
- </tr>
- </table>
-</form>
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/msg.index b/roundup/templates/classic/html/msg.index
+++ /dev/null
@@ -1,23 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">
- <span tal:replace="config/TRACKER_NAME" />: List of messages
-</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>Message listing</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-<table class="messages" tal:condition="request/filter">
- <tr><th colspan=2 class="header">Messages</th></tr>
- <tal:block tal:repeat="msg context/list">
- <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>
-</table>
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/msg.item b/roundup/templates/classic/html/msg.item
+++ /dev/null
@@ -1,58 +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">
-<span tal:replace="config/TRACKER_NAME" />:
-<span tal:condition="context/id" tal:replace="string:Message ${context/id}" />
-<tal:x tal:condition="not:context/id">New Message</tal:x>
-</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>
- Message<span tal:replace="context/id" />
- <tal:x tal:condition="context/is_edit_ok">Editing</tal:x>
- </h2>
-</td>
-<td class="content" metal:fill-slot="content">
-<table class="form">
-
-<tr>
- <th nowrap>Author</th>
- <td tal:content="context/author"></td>
-</tr>
-
-<tr>
- <th nowrap>Recipients</th>
- <td tal:content="context/recipients"></td>
-</tr>
-
-<tr>
- <th nowrap>Date</th>
- <td tal:content="context/date"></td>
-</tr>
-</table>
-
-<table class="messages">
- <tr><th colspan=2 class="header">Content</th></tr>
- <tr>
- <td class="content" colspan=2><pre tal:content="context/content"></pre></td>
- </tr>
-</table>
-
-<table class="files" tal:condition="context/files">
- <tr><th colspan="2" class="header">Files</th></tr>
- <tr><th>File name</th><th>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" />
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/page b/roundup/templates/classic/html/page
+++ /dev/null
@@ -1,104 +0,0 @@
-<html metal:define-macro="icing">
-<head>
-<title metal:define-slot="head_title">title goes here</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
-
-<link rel="stylesheet" type="text/css" href="_file/style.css">
-
-<script tal:replace="structure request/base_javascript">
-</script>
-
-</head>
-<body class="body" marginwidth="0" marginheight="0">
-
-<table class="body">
-
-<tr>
- <td class="page-header-left"> </td>
- <td class="page-header-top" metal:define-slot="body_title"><h2>name</h2></td>
-</tr>
-
-<tr>
- <td rowspan="2" valign="top" nowrap class="sidebar">
- <p class="classblock" tal:condition="request/user/queries">
- <b>Your Queries</b><br>
- <tal:block tal:repeat="qs request/user/queries">
- <a tal:attributes="href string:${qs/klass}${qs/url}"
- tal:content="qs/name">link</a><br>
- </tal:block>
- </p>
-
- <form method="POST">
- <p class="classblock"
- tal:condition="python:request.user.hasPermission('View', 'issue')">
- <b>Issues</b><br>
- <a tal:condition="python:request.user.hasPermission('Edit', 'issue')"
- href="issue?:template=item">Create New<br></a>
- <a href="issue?:sort=-activity&:group=priority&:filter=status,assignedto&:columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=-1">Show Unassigned</a><br>
- <a href="issue?:sort=-activity&:group=priority&:filter=status&:columns=id,activity,title,creator,assignedto,status&status=-1,1,2,3,4,5,6,7">Show All</a><br>
- <a href="issue?:template=search">Search</a><br>
- <input type="submit" value="Show issue no."><input 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:request.user.hasPermission('View', 'keyword')">
- <b>Keywords</b><br>
- <a tal:condition="python:request.user.hasPermission('Edit', 'keyword')"
- href="keyword?:template=item">Create New<br></a>
- <a tal:condition="python:request.user.hasPermission('Edit', 'keyword') and
- len(db.keyword.list())"
- href="keyword?:template=item">Edit Existing<br></a>
- </p>
-
- <p class="classblock"
- tal:condition="python:request.user.username != 'anonymous'">
- <b>Administration</b><br>
- <a tal:condition="python:request.user.hasPermission('Edit', None)"
- href="home?:template=classlist">Class List</a><br>
- <a tal:condition="python:request.user.hasPermission('View', 'user')
- or request.user.hasPermission('Edit', 'user')"
- href="user" >User List</a><br>
- <a tal:condition="python:request.user.hasPermission('Edit', 'user')"
- href="user?:template=item">Add User</a>
- </p>
-
- <form method="POST" action="">
- <p class="userblock" tal:condition="python:request.user.username=='anonymous'">
- <input size="10" name="__login_name"><br>
- <input size="10" type="password" name="__login_password"><br>
- <input type="submit" name=":action" value="login">
- <span tal:replace="structure request/indexargs_form" />
- <a href="user?:template=register">Register</a><br>
- <a href="user?:template=forgotten">Forgotten your password?</a><br>
- </p>
- </form>
-
- <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
- <b>Hello,</b><br><b tal:content="request/user/username">username</b><br>
- <a tal:attributes="href string:issue?:sort=-activity&:group=priority&:filter=status,assignedto&:columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=${request/user/id}">My Issues</a><br>
- <a tal:attributes="href string:user${request/user/id}">My Details</a><br>
- <a tal:attributes="href python:request.indexargs_href('',
- {':action':'logout'})">Logout</a>
- </p>
- </td>
- <td>
- <p tal:condition="options/error_message | nothing" class="error-message"
- tal:repeat="m options/error_message" tal:content="structure m">error</p>
- <p tal:condition="options/ok_message | nothing" class="ok-message"
- tal:repeat="m options/ok_message" tal:content="structure m">error</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>
diff --git a/roundup/templates/classic/html/query.item b/roundup/templates/classic/html/query.item
+++ /dev/null
@@ -1,3 +0,0 @@
-<!-- query.item -->
-<span tal:content="structure context/renderQueryForm" />
-
diff --git a/roundup/templates/classic/html/style.css b/roundup/templates/classic/html/style.css
+++ /dev/null
@@ -1,308 +0,0 @@
-/* main page styles */
-body.body {
- font-family: sans-serif, Arial, Helvetica;
- color: #333333;
-}
-a[href]:hover { color:blue; text-decoration: underline; }
-a[href]:link { color:blue; text-decoration: none; }
-a[href] { color:blue; text-decoration: none; }
-
-table.body {
- border: 0;
- padding: 0;
- border-spacing: 0px;
- border-collapse: separate;
-}
-
-td.page-header-left {
- padding: 5px;
- border-bottom: 1px solid #444444;
-}
-
-td.page-header-top {
- padding: 5px;
- border-bottom: 1px solid #444444;
-}
-
-td.sidebar {
- padding: 1 0 0 1;
-}
-
-td.sidebar p.classblock {
- padding: 0 5 0 5;
- margin: 1 1 1 1;
- border: 1px solid #444444;
- background-color: #eeeeee;
-}
-
-td.sidebar p.userblock {
- padding: 0 5 0 5;
- margin: 1 1 1 1;
- border: 1px solid #444444;
- background-color: #eeeeff;
-}
-
-td.content {
- padding: 1 5 1 5;
- vertical-align: top;
- width: 100%;
-}
-
-p.ok-message {
- background-color: #22bb22;
- padding: 5 5 5 5;
- color: white;
- font-weight: bold;
-}
-p.error-message {
- background-color: #bb2222;
- padding: 5 5 5 5;
- color: white;
- font-weight: bold;
-}
-
-
-/* style for forms */
-table.form {
- padding: 2;
- border-spacing: 0px;
- border-collapse: separate;
-}
-
-table.form th {
- color: #333388;
- text-align: right;
- vertical-align: top;
- font-weight: normal;
-}
-
-table.form th.header {
- font-weight: bold;
- background-color: #eeeeff;
- text-align: left;
-}
-
-table.form th.required {
- font-weight: bold;
-}
-
-table.form td {
- color: #333333;
- empty-cells: show;
- vertical-align: top;
-}
-
-table.form td.optional {
- font-weight: bold;
- font-style: italic;
-}
-
-table.form td.html {
- color: #777777;
-}
-
-/* style for lists */
-table.list {
- border-spacing: 0px;
- border-collapse: separate;
- width: 100%;
-}
-
-table.list th {
- padding: 0 4 0 4;
- color: #404070;
- background-color: #eeeeff;
- 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 4 0 4;
- border: 1px solid white;
- color: #404070;
- background-color: white;
- vertical-align: top;
- empty-cells: show;
-}
-
-table.list tr.normal td {
- background-color: #efefef;
-}
-
-table.list tr.alt td {
- background-color: #efefef;
-}
-
-table.list tr.navigation th {
- text-align: right;
-}
-table.list tr.navigation th:first-child {
- text-align: left;
-}
-
-
-/* style for message displays */
-table.messages {
- border-spacing: 0px;
- 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: 2 5 2 5;
-}
-
-table.messages td:first-child {
- border-left: 1px solid #afafaf;
- border-right: 1px solid #afafaf;
-}
-
-/* style for file displays */
-table.files {
- border-spacing: 0px;
- 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: 0px;
- 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: 0px;
- 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 {
- border-spacing: 0px;
- border-collapse: separate;
- width: 100%;
-}
-
-table.classhelp th {
- font-weight: bold;
- text-align: left;
- color: #707040;
-}
-
-table.classhelp td {
- padding: 2 2 2 2;
- border: 1px solid black;
- text-align: left;
- vertical-align: top;
- empty-cells: show;
-}
-
-
-/* style for "other" displays */
-table.otherinfo {
- border-spacing: 0px;
- 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/roundup/templates/classic/html/user.forgotten b/roundup/templates/classic/html/user.forgotten
+++ /dev/null
@@ -1,33 +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">Password reset request</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>Password reset request</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<p>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()">
-<input type="hidden" name="@action" value="passrst">
-<input type="hidden" name="@template" value="forgotten">
-<table class="form">
- <tr><th>Email Address:</th> <td><input name="address"></td> </tr>
- <tr><td></td><td><input type="submit" value="Request password reset"></td></tr>
-</table>
-
-<p>Or, if you know your username, then enter it below.</p>
-
-<table class="form">
- <tr><th>Username:</th> <td><input name="username"></td> </tr>
- <tr><td></td><td><input type="submit" value="Request password reset"></td></tr>
-</table>
-</form>
-
-<p>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/roundup/templates/classic/html/user.index b/roundup/templates/classic/html/user.index
+++ /dev/null
@@ -1,40 +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">User listing</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>User listing</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="not:context/is_view_ok">
-You are not allowed to view this page.
-</span>
-
-<table width="100%" tal:condition="context/is_view_ok" class="list">
-<tr>
- <th>Username</th>
- <th>Real name</th>
- <th>Organisation</th>
- <th>Email address</th>
- <th>Phone number</th>
- <th tal:condition="context/is_edit_ok">Retire</th>
-</tr>
-<tr tal:repeat="user context/list"
- 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="user/realname">realname</td>
- <td tal:content="user/organisation">organisation</td>
- <td tal:content="python:user.address.email()">address</td>
- <td tal:content="user/phone">phone</td>
- <td tal:condition="context/is_edit_ok">
- <a tal:attributes="href string:user${user/id}?:action=retire&:template=index">
- retire</a>
- </td>
-</tr>
-</table>
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/user.item b/roundup/templates/classic/html/user.item
+++ /dev/null
@@ -1,126 +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">
-<span tal:replace="config/TRACKER_NAME" />:
-<span tal:condition="context/id"
- tal:replace="string:User ${context/id}: ${context/username}" />
-<tal:x tal:condition="not:context/id">New User</tal:x>
-</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>
- User<span tal:replace="context/id" />
- <tal:x tal:condition="context/is_edit_ok">Editing</tal:x>
- </h2>
-</td>
-
-<td class="content" metal:fill-slot="content">
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<input type="hidden" name=":required" value="username,address">
-
-<table class="form">
- <tr>
- <th>Name</th>
- <td tal:content="structure context/realname/field">realname</td>
- </tr>
- <tr>
- <th>Login Name</th>
- <td tal:content="structure context/username/field">username</td>
- </tr>
- <tr>
- <th>Login Password</th>
- <td tal:content="structure context/password/field">password</td>
- </tr>
- <tr>
- <th>Confirm Password</th>
- <td tal:content="structure context/password/confirm">password</td>
- </tr>
- <tr tal:condition="python:request.user.hasPermission('Web Roles')">
- <th>Roles</th>
- <td tal:condition="context/id"
- tal:content="structure context/roles/field">roles</td>
- <td tal:condition="not:context/id">
- <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
- (to give the user more than one role, enter a comma,separated,list)
- </td>
- </tr>
- <tr>
- <th>Phone</th>
- <td tal:content="structure context/phone/field">phone</td>
- </tr>
- <tr>
- <th>Organisation</th>
- <td tal:content="structure context/organisation/field">organisation</td>
- </tr>
- <tr>
- <th>Timezone</th>
- <td tal:content="structure context/timezone/field">timezone</td>
- </tr>
- <tr>
- <th>E-mail address</th>
- <td tal:content="structure context/address/field">address</td>
- </tr>
- <tr>
- <th>Alternate E-mail addresses<br>One address per line</th>
- <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
- </tr>
-
- <tr>
- <td> </td>
- <td tal:content="structure context/submit">submit button here</td>
- </tr>
-</table>
-</form>
-
-<table class="otherinfo" tal:condition="context/queries">
- <tr><th colspan="3" class="header">Queries</th></tr>
- <tr><th>Name</th><th colspan="2">Actions</th></tr>
- <tr tal:repeat="query context/queries">
- <td><a tal:attributes="href string:query${query/id}"
- tal:content="query/name"></a></td>
- <td>
- <a tal:attributes="href python:'%s%s'%(query['klass'], query['url'])">display</a>
- </td>
- <td>
- <a tal:attributes="href string:?:remove:queries=${query/id}&:action=edit">remove</a>
- </td>
- </tr>
-</table>
-
-<table class="form" tal:condition="context/is_only_view_ok">
- <tr>
- <th colspan=2 class="header" tal:content="context/realname">realname</th>
- </tr>
- <tr>
- <th>Login Name</th>
- <td tal:content="context/username">username</td>
- </tr>
- <tr>
- <th>Phone</th>
- <td tal:content="context/phone">phone</td>
- </tr>
- <tr>
- <th>Organisation</th>
- <td tal:content="context/organisation">organisation</td>
- </tr>
- <tr>
- <th>Timezone</th>
- <td tal:content="context/timezone">timezone</td>
- </tr>
- <tr>
- <th>E-mail address</th>
- <td tal:content="context/address/email">address</td>
- </tr>
-</table>
-
-<tal:block tal:condition="python:context.id and context.is_view_ok()"
- tal:replace="structure context/history" />
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/user.register b/roundup/templates/classic/html/user.register
+++ /dev/null
@@ -1,82 +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"
- tal:content="string:Registering with ${db/config/TRACKER_NAME}"></title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2 tal:content="string:Registering with ${db/config/TRACKER_NAME}"></h2>
-</td>
-<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">
-You are not allowed to view this page.
-</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>Name</th>
- <td tal:content="structure context/realname/field">realname</td>
- </tr>
- <tr>
- <th>Login Name</th>
- <td tal:content="structure context/username/field">username</td>
- </tr>
- <tr>
- <th>Login Password</th>
- <td tal:content="structure context/password/field">password</td>
- </tr>
- <tr>
- <th>Confirm Password</th>
- <td tal:content="structure context/password/confirm">password</td>
- </tr>
- <tr tal:condition="python:request.user.hasPermission('Web Roles')">
- <th>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>Phone</th>
- <td tal:content="structure context/phone/field">phone</td>
- </tr>
- <tr>
- <th>Organisation</th>
- <td tal:content="structure context/organisation/field">organisation</td>
- </tr>
- <tr>
- <th>E-mail address</th>
- <td tal:content="structure context/address/field">address</td>
- </tr>
- <tr>
- <th>Alternate E-mail addresses<br>One address per line</th>
- <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
- </tr>
-
- <tr>
- <td> </td>
- <td>
- <input type="hidden" name=":action" value="register">
- <input type="submit" name="submit" value="Register">
- </td>
- </tr>
-</table>
-</form>
-
-</tal:block>
-
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/classic/html/user.rego_progress b/roundup/templates/classic/html/user.rego_progress
+++ /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">List of issues</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h1>Registration in progress...</h1>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<p>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/roundup/templates/classic/interfaces.py b/roundup/templates/classic/interfaces.py
+++ /dev/null
@@ -1,41 +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: interfaces.py,v 1.16 2002-10-11 01:26:43 richard Exp $
-
-from roundup import mailgw
-from roundup.cgi import client
-
-class Client(client.Client):
- ''' derives basic CGI implementation from the standard module,
- with any specific extensions
- '''
- pass
-
-class TemplatingUtils:
- ''' Methods implemented on this class will be available to HTML templates
- through the 'utils' variable.
- '''
- pass
-
-class MailGW(mailgw.MailGW):
- ''' derives basic mail gateway implementation from the standard module,
- with any specific extensions
- '''
- pass
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/minimal/.cvsignore b/roundup/templates/minimal/.cvsignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*.pyc
-*.pyo
-htmlbase.py
-*.cover
diff --git a/roundup/templates/minimal/__init__.py b/roundup/templates/minimal/__init__.py
+++ /dev/null
@@ -1,24 +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: __init__.py,v 1.1 2002-09-26 04:15:07 richard Exp $
-
-import config
-from dbinit import open, init
-from interfaces import Client, MailGW
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/minimal/config.py b/roundup/templates/minimal/config.py
+++ /dev/null
@@ -1,99 +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: config.py,v 1.5 2003-01-12 00:41:27 richard Exp $
-
-import os
-
-# roundup home is this package's directory
-TRACKER_HOME=os.path.split(__file__)[0]
-
-# The SMTP mail host that roundup will use to send mail
-MAILHOST = 'localhost'
-
-# The domain name used for email addresses.
-MAIL_DOMAIN = 'your.tracker.email.domain.example'
-
-# This is the directory that the database is going to be stored in
-DATABASE = os.path.join(TRACKER_HOME, 'db')
-
-# This is the directory that the HTML templates reside in
-TEMPLATES = os.path.join(TRACKER_HOME, 'html')
-
-# A descriptive name for your roundup instance
-TRACKER_NAME = 'Roundup issue tracker'
-
-# The email address that mail to roundup should go to
-TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
-
-# The web address that the tracker is viewable at. This will be included in
-# information sent to users of the tracker. The URL MUST include the cgi-bin
-# part or anything else that is required to get to the home page of the
-# tracker. You MUST include a trailing '/' in the URL.
-TRACKER_WEB = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/'
-
-# The email address that roundup will complain to if it runs into trouble
-ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
-
-# Additional text to include in the "name" part of the From: address used
-# in nosy messages. If the sending user is "Foo Bar", the From: line is
-# usually: "Foo Bar" <issue_tracker@tracker.example>
-# the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
-# "Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>
-EMAIL_FROM_TAG = ""
-
-#
-# SECURITY DEFINITIONS
-#
-# define the Roles that a user gets when they register with the tracker
-# these are a comma-separated string of role names (e.g. 'Admin,User')
-NEW_WEB_USER_ROLES = 'User'
-NEW_EMAIL_USER_ROLES = 'User'
-
-# Send nosy messages to the author of the message
-MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no'
-
-# Does the author of a message get placed on the nosy list automatically?
-# If 'new' is used, then the author will only be added when a message
-# creates a new issue. If 'yes', then the author will be added on followups
-# too. If 'no', they're never added to the nosy.
-ADD_AUTHOR_TO_NOSY = 'new' # one of 'yes', 'no', 'new'
-
-# Do the recipients (To:, Cc:) of a message get placed on the nosy list?
-# If 'new' is used, then the recipients will only be added when a message
-# creates a new issue. If 'yes', then the recipients will be added on followups
-# too. If 'no', they're never added to the nosy.
-ADD_RECIPIENTS_TO_NOSY = 'new' # either 'yes', 'no', 'new'
-
-# Where to place the email signature
-EMAIL_SIGNATURE_POSITION = 'bottom' # one of 'top', 'bottom', 'none'
-
-# Keep email citations when accepting messages. Setting this to "no" strips
-# out "quoted" text from the message. Signatures are also stripped.
-EMAIL_KEEP_QUOTED_TEXT = 'yes' # either 'yes' or 'no'
-
-# Preserve the email body as is - that is, keep the citations _and_
-# signatures.
-EMAIL_LEAVE_BODY_UNCHANGED = 'no' # either 'yes' or 'no'
-
-# Default class to use in the mailgw if one isn't supplied in email
-# subjects. To disable, comment out the variable below or leave it blank.
-# Examples:
-MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default
-#MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out)
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/minimal/dbinit.py b/roundup/templates/minimal/dbinit.py
+++ /dev/null
@@ -1,112 +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: dbinit.py,v 1.3 2002-10-10 07:17:39 richard Exp $
-
-import os
-
-import config
-from select_db import Database, Class, FileClass, IssueClass
-
-def open(name=None):
- ''' as from the roundupdb method openDB
- '''
- from roundup.hyperdb import String, Password, Date, Link, Multilink
- from roundup.hyperdb import Interval, Boolean, Number
-
- # open the database
- db = Database(config, name)
-
- #
- # Now initialise the schema. Must do this each time the database is
- # opened.
- #
-
- # 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")
-
- # add any additional database schema configuration here
-
- #
- # SECURITY SETTINGS
- #
- # new permissions for this schema
- for cl in ('user', ):
- db.security.addPermission(name="Edit", klass=cl,
- description="User is allowed to edit "+cl)
- db.security.addPermission(name="View", klass=cl,
- description="User is allowed to access "+cl)
-
- # and give the regular users access to the web and email interface
- p = db.security.getPermission('Web Access')
- db.security.addPermissionToRole('User', p)
- p = db.security.getPermission('Email Access')
- db.security.addPermissionToRole('User', p)
-
- # May users view other user information? Comment these lines out
- # if you don't want them to
- p = db.security.getPermission('View', 'user')
- db.security.addPermissionToRole('User', p)
-
- # Assign the appropriate permissions to the anonymous user's Anonymous
- # Role. Choices here are:
- # - Allow anonymous users to register through the web
- p = db.security.getPermission('Web Registration')
- db.security.addPermissionToRole('Anonymous', p)
- # - Allow anonymous (new) users to register through the email gateway
- p = db.security.getPermission('Email Registration')
- db.security.addPermissionToRole('Anonymous', p)
-
- import detectors
- detectors.init(db)
-
- # schema is set up - run any post-initialisation
- db.post_init()
- return db
-
-def init(adminpw):
- ''' as from the roundupdb method initDB
-
- Open the new database, and add new nodes - used for initialisation. You
- can edit this before running the "roundup-admin initialise" command to
- change the initial database entries.
- '''
- dbdir = os.path.join(config.DATABASE, 'files')
- if not os.path.isdir(dbdir):
- os.makedirs(dbdir)
-
- db = open("admin")
- db.clear()
-
- # create the two default users
- user = db.getclass('user')
- user.create(username="admin", password=adminpw,
- address=config.ADMIN_EMAIL, roles='Admin')
- user.create(username="anonymous", roles='Anonymous')
-
- # add any additional database create steps here - but only if you
- # haven't initialised the database with the admin "initialise" command
-
- db.commit()
-
-# vim: set filetype=python ts=4 sw=4 et si
-
diff --git a/roundup/templates/minimal/detectors/.cvsignore b/roundup/templates/minimal/detectors/.cvsignore
+++ /dev/null
@@ -1,3 +0,0 @@
-*.pyc
-*.pyo
-*.cover
diff --git a/roundup/templates/minimal/detectors/__init__.py b/roundup/templates/minimal/detectors/__init__.py
+++ /dev/null
@@ -1,37 +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: __init__.py,v 1.2 2003-02-20 07:04:55 richard Exp $
-
-import sys, os, imp
-
-def init(db):
- ''' execute the init functions of all the modules in this directory
- '''
- this_dir = os.path.split(__file__)[0]
- for file in os.listdir(this_dir):
- path = os.path.join(this_dir, file)
- name, ext = os.path.splitext(file)
- if name == '__init__':
- continue
- if ext == '.py':
- module = imp.load_module(name, open(path), file,
- ('.py', 'r', imp.PY_SOURCE))
- print (name, open(path), file, module)
- module.init(db)
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/templates/minimal/html/_generic.help b/roundup/templates/minimal/html/_generic.help
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
-<link rel="stylesheet" type="text/css" href="_file/style.css">
-</head>
-<body class="body" marginwidth="0" marginheight="0">
-
-<table class="classhelp"
- tal:define="props python:request.form['properties'].value.split(',')">
-<tr><th tal:repeat="prop props" tal:content="prop"></th></tr>
-<tr tal:repeat="item context/list">
- <td tal:repeat="prop props" tal:content="python:item[prop]"></td>
-</tr>
-</table>
-
-</body>
diff --git a/roundup/templates/minimal/html/_generic.index b/roundup/templates/minimal/html/_generic.index
+++ /dev/null
@@ -1,48 +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"
- tal:content="python:context._classname.capitalize()+' editing'"></title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<tal:block tal:condition="context/is_edit_ok">
-<p class="form-help">
- You may edit the contents of the <span tal:replace="request/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>
-
-<form onSubmit="return submit_once()" method="POST">
-<textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea>
-<br>
-<input type="hidden" name=":action" value="editCSV">
-<input type="submit" value="Edit Items">
-</form>
-</tal:block>
-
-<tal:block tal:condition="context/is_only_view_ok">
-view ok
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/minimal/html/_generic.item b/roundup/templates/minimal/html/_generic.item
+++ /dev/null
@@ -1,56 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title"
- tal:content="python:context._classname.capitalize()+' editing'"></title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<input type="hidden" name=":template" value="item">
-<input type="hidden" name=":required" value="title">
-
-<table class="form">
-
-<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>
-<tr>
- <td> </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/roundup/templates/minimal/html/home b/roundup/templates/minimal/html/home
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">Tracker home</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>Tracker home</h2>
-</td>
-<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">
-Please select from one of the menu options on the right.
-</p>
-<p tal:condition="anon" class="help">
-Please log in or register.
-</p>
-</tal:block>
-
-</td>
-</tal:block>
diff --git a/roundup/templates/minimal/html/home.classlist b/roundup/templates/minimal/html/home.classlist
+++ /dev/null
@@ -1,25 +0,0 @@
-<tal:block metal:use-macro="templates/page/macros/icing">
-<title metal:fill-slot="head_title">List of classes</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>List of classes</h2>
-</td>
-<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/roundup/templates/minimal/html/page b/roundup/templates/minimal/html/page
+++ /dev/null
@@ -1,69 +0,0 @@
-<html metal:define-macro="icing">
-<head>
-<title metal:define-slot="head_title">title goes here</title>
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
-
-<link rel="stylesheet" type="text/css" href="_file/style.css">
-
-<script tal:replace="structure request/base_javascript">
-</script>
-
-</head>
-<body class="body" marginwidth="0" marginheight="0">
-
-<table class="body">
-
-<tr>
- <td class="page-header-left"> </td>
- <td class="page-header-top" metal:define-slot="body_title"><h2>name</h2></td>
-</tr>
-
-<tr>
- <td rowspan="2" valign="top" nowrap class="sidebar">
- <p class="userblock" tal:condition="python:request.user.username=='anonymous'">
- <form method="POST" action="">
- <input size="10" name="__login_name"><br>
- <input size="10" type="password" name="__login_password"><br>
- <input type="submit" name=":action" value="login">
- <span tal:replace="structure request/indexargs_form" />
- </form>
- <a href="user?:template=register">Register</a>
- </p>
-
- <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
- <b>Hello,</b><br><b tal:content="request/user/username">username</b><br>
- <a tal:attributes="href string:user${request/user/id}">My Details</a><br>
- <a tal:attributes="href python:request.indexargs_href('',
- {':action':'logout'})">Logout</a>
- </p>
-
- <p class="classblock"
- tal:condition="python:request.user.username != 'anonymous'">
- <b>Administration</b><br>
- <a tal:condition="python:request.user.hasPermission('Edit', None)"
- href="home?:template=classlist">Class List</a><br>
- <a tal:condition="python:request.user.hasPermission('View', 'user')
- or request.user.hasPermission('Edit', 'user')"
- href="user" >User List</a><br>
- <a tal:condition="python:request.user.hasPermission('Edit', 'user')"
- href="user?:template=item">Add User</a>
- </p>
- </td>
- <td>
- <p tal:condition="options/error_message | nothing" class="error-message"
- tal:repeat="m options/error_message" tal:content="structure m">error</p>
- <p tal:condition="options/ok_message | nothing" class="ok-message"
- tal:repeat="m options/ok_message" tal:content="structure m">error</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>
diff --git a/roundup/templates/minimal/html/style.css b/roundup/templates/minimal/html/style.css
+++ /dev/null
@@ -1,319 +0,0 @@
-/* main page styles */
-body.body {
- font-family: sans-serif, Arial, Helvetica;
- color: #333333;
-}
-a[href]:hover { color:blue; text-decoration: underline; }
-a[href]:link { color:blue; text-decoration: none; }
-a[href] { color:blue; text-decoration: none; }
-
-table.body {
- border: 0;
- padding: 0;
- border-spacing: 0px;
- border-collapse: separate;
-}
-
-td.page-header-left {
- padding: 5px;
- border-bottom: 1px solid #444444;
-}
-
-td.page-header-top {
- padding: 5px;
- border-bottom: 1px solid #444444;
-}
-
-td.sidebar {
- padding: 1 0 0 1;
-}
-
-td.sidebar p.classblock {
- padding: 0 5 0 5;
- margin: 1 1 1 1;
- border: 1px solid #444444;
- background-color: #eeeeee;
-}
-
-td.sidebar p.userblock {
- padding: 0 5 0 5;
- margin: 1 1 1 1;
- border: 1px solid #444444;
- background-color: #eeeeff;
-}
-
-td.content {
- padding: 1 5 1 5;
- vertical-align: top;
- width: 100%;
-}
-
-p.ok-message {
- background-color: #22bb22;
- padding: 5 5 5 5;
- color: white;
- font-weight: bold;
-}
-p.error-message {
- background-color: #bb2222;
- padding: 5 5 5 5;
- color: white;
- font-weight: bold;
-}
-
-
-/* style for forms */
-table.form {
- padding: 2;
- border-spacing: 0px;
- border-collapse: separate;
-}
-
-table.form th {
- font-weight: bold;
- color: #333388;
- text-align: right;
- vertical-align: top;
-}
-
-table.form th.header {
- font-weight: bold;
- color: #333388;
- background-color: #eeeeff;
- text-align: left;
-}
-
-table.form td {
- color: #333333;
- empty-cells: show;
- vertical-align: top;
-}
-
-table.form td.optional {
- font-weight: bold;
- font-style: italic;
-}
-
-table.form td.html {
- color: #777777;
-}
-
-/* style for lists */
-table.list {
- border-spacing: 0px;
- border-collapse: separate;
- width: 100%;
-}
-
-table.list th {
- padding: 0 4 0 4;
- color: #404070;
- background-color: #eeeeff;
- border-right: 1px solid #404070;
- border-top: 1px solid #404070;
- border-bottom: 1px solid #404070;
- 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 4 0 4;
- border: 0 2 0 2;
- border-right: 1px solid #404070;
- color: #404070;
- background-color: white;
- vertical-align: top;
- empty-cells: show;
-}
-
-table.list tr.normal td {
- background-color: white;
-}
-
-table.list tr.alt td {
- background-color: #efefef;
-}
-
-table.list td:first-child {
- border-left: 1px solid #404070;
- border-right: 1px solid #404070;
-}
-
-table.list th:first-child {
- border-left: 1px solid #404070;
- border-right: 1px solid #404070;
-}
-
-table.list tr.navigation th {
- text-align: right;
-}
-table.list tr.navigation th:first-child {
- border-right: none;
- text-align: left;
-}
-
-
-/* style for message displays */
-table.messages {
- border-spacing: 0px;
- 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: 2 5 2 5;
-}
-
-table.messages td:first-child {
- border-left: 1px solid #afafaf;
- border-right: 1px solid #afafaf;
-}
-
-/* style for file displays */
-table.files {
- border-spacing: 0px;
- 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: 0px;
- 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: 0px;
- 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 {
- border-spacing: 0px;
- border-collapse: separate;
- width: 100%;
-}
-
-table.classhelp th {
- font-weight: bold;
- text-align: left;
- color: #707040;
-}
-
-table.classhelp td {
- padding: 2 2 2 2;
- border: 1px solid black;
- text-align: left;
- vertical-align: top;
- empty-cells: show;
-}
-
-
-/* style for "other" displays */
-table.otherinfo {
- border-spacing: 0px;
- 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/roundup/templates/minimal/html/user.index b/roundup/templates/minimal/html/user.index
+++ /dev/null
@@ -1,29 +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">User listing</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>User listing</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-
-<span tal:condition="not:context/is_view_ok">
-You are not allowed to view this page.
-</span>
-
-<table width="100%" tal:condition="context/is_view_ok" class="list">
-<tr>
- <th>Username</th>
- <th>Email address</th>
-</tr>
-<tr tal:repeat="user context/list"
- 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>
-</table>
-</td>
-
-</tal:block>
diff --git a/roundup/templates/minimal/html/user.item b/roundup/templates/minimal/html/user.item
+++ /dev/null
@@ -1,70 +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">User editing</title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2>User editing</h2>
-</td>
-<td class="content" metal:fill-slot="content">
-<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
-You are not allowed to view this page.
-</span>
-
-<form method="POST" onSubmit="return submit_once()"
- enctype="multipart/form-data" tal:condition="context/is_edit_ok">
-
-<input type="hidden" name=":required" value="username,address">
-
-<table class="form">
- <tr>
- <th>Login Name</th>
- <td tal:content="structure context/username/field">username</td>
- </tr>
- <tr>
- <th>Login Password</th>
- <td tal:content="structure context/password/field">password</td>
- </tr>
- <tr>
- <th>Confirm Password</th>
- <td tal:content="structure context/password/confirm">password</td>
- </tr>
- <tr tal:condition="python:request.user.hasPermission('Web Roles')">
- <th>Roles</th>
- <td tal:condition="context/id"
- tal:content="structure context/roles/field">roles</td>
- <td tal:condition="not:context/id">
- <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
- </td>
- </tr>
- <tr>
- <th>E-mail address</th>
- <td tal:content="structure context/address/field">address</td>
- </tr>
- <tr>
- <th>Alternate E-mail addresses<br>One address per line</th>
- <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
- </tr>
-
- <tr>
- <td> </td>
- <td tal:content="structure context/submit">submit button here</td>
- </tr>
-</table>
-</form>
-
-<table class="form" tal:condition="context/is_only_view_ok">
- <tr>
- <th>Login Name</th>
- <td tal:content="context/username">username</td>
- </tr>
- <tr>
- <th>E-mail address</th>
- <td tal:content="context/address/email">address</td>
- </tr>
-</table>
-
-<tal:block tal:condition="python:context.id and context.is_view_ok()"
- tal:replace="structure context/history" />
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/minimal/html/user.register b/roundup/templates/minimal/html/user.register
+++ /dev/null
@@ -1,82 +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"
- tal:content="string:Registering with ${db/config/TRACKER_NAME}"></title>
-<td class="page-header-top" metal:fill-slot="body_title">
- <h2 tal:content="string:Registering with ${db/config/TRACKER_NAME}"></h2>
-</td>
-<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">
-You are not allowed to view this page.
-</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>Name</th>
- <td tal:content="structure context/realname/field">realname</td>
- </tr>
- <tr>
- <th>Login Name</th>
- <td tal:content="structure context/username/field">username</td>
- </tr>
- <tr>
- <th>Login Password</th>
- <td tal:content="structure context/password/field">password</td>
- </tr>
- <tr>
- <th>Confirm Password</th>
- <td tal:content="structure context/password/confirm">password</td>
- </tr>
- <tr tal:condition="python:request.user.hasPermission('Web Roles')">
- <th>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>Phone</th>
- <td tal:content="structure context/phone/field">phone</td>
- </tr>
- <tr>
- <th>Organisation</th>
- <td tal:content="structure context/organisation/field">organisation</td>
- </tr>
- <tr>
- <th>E-mail address</th>
- <td tal:content="structure context/address/field">address</td>
- </tr>
- <tr>
- <th>Alternate E-mail addresses<br>One address per line</th>
- <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
- </tr>
-
- <tr>
- <td> </td>
- <td>
- <input type="hidden" name=":action" value="register">
- <input type="submit" name="submit" value="Register">
- </td>
- </tr>
-</table>
-</form>
-
-</tal:block>
-
-</tal:block>
-
-</td>
-
-</tal:block>
diff --git a/roundup/templates/minimal/interfaces.py b/roundup/templates/minimal/interfaces.py
+++ /dev/null
@@ -1,41 +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: interfaces.py,v 1.2 2002-10-11 01:26:43 richard Exp $
-
-from roundup import mailgw
-from roundup.cgi import client
-
-class Client(client.Client):
- ''' derives basic CGI implementation from the standard module,
- with any specific extensions
- '''
- pass
-
-class TemplatingUtils:
- ''' Methods implemented on this class will be available to HTML templates
- through the 'utils' variable.
- '''
- pass
-
-class MailGW(mailgw.MailGW):
- ''' derives basic mail gateway implementation from the standard module,
- with any specific extensions
- '''
- pass
-
-# vim: set filetype=python ts=4 sw=4 et si
diff --git a/setup.py b/setup.py
index 08bfe4407288dfb82e94ee563a6e4dc1cbcff83e..bb1d8a3c7cd99eab0da95e587528b6ac13ad270b 100644 (file)
--- a/setup.py
+++ b/setup.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: setup.py,v 1.47 2003-04-17 01:14:10 richard Exp $
+# $Id: setup.py,v 1.48 2003-04-17 03:37:57 richard Exp $
from distutils.core import setup, Extension
from distutils.util import get_platform
DistributionMetadata.classifiers = None
DistributionMetadata.download_url = None
-from roundup.templates.builder import makeHtmlBase
-
#############################################################################
### Build script files
### Main setup stuff
#############################################################################
-def isTemplateDir(dir):
- return dir[0] != '.' and dir != 'CVS' and os.path.isdir(dir) \
- and os.path.isfile(os.path.join(dir, '__init__.py'))
-
-# use that function to list all the templates
-templates = map(os.path.basename, filter(isTemplateDir,
- glob(os.path.join('roundup', 'templates', '*'))))
-
-def buildTemplates():
- for template in templates:
- tdir = os.path.join('roundup', 'templates', template)
- makeHtmlBase(tdir)
-
def main():
# build list of scripts from their implementation modules
roundup_scripts = map(scriptname, glob('roundup/scripts/[!_]*.py'))
# template munching
- templates = map(os.path.basename, filter(isTemplateDir,
- glob(os.path.join('roundup', 'templates', '*'))))
packagelist = [
'roundup',
'roundup.cgi',
'roundup.cgi.TAL',
'roundup.cgi.ZTUtils',
'roundup.backends',
- 'roundup.scripts',
- 'roundup.templates'
+ 'roundup.scripts'
]
installdatafiles = [
('share/roundup/cgi-bin', ['cgi-bin/roundup.cgi']),
installdatafiles.append(('man/man1', ['doc/roundup-admin.1',
'doc/roundup-mailgw.1', 'doc/roundup-server.1']))
- # munge the template HTML into the htmlbase module
- buildTemplates()
-
- # add the templates to the setup packages and data files lists
- for template in templates:
- tdir = os.path.join('roundup', 'templates', template)
-
- # add the template package and subpackage
- packagelist.append('roundup.templates.%s' % template)
- packagelist.append('roundup.templates.%s.detectors' % template)
-
+ # add the templates to the data files lists
+ from roundup.admin import listTemplates
+ templates = [t['path'] for t in listTemplates('.').values()]
+ for tdir in templates:
# scan for data files
- tfiles = glob(os.path.join(tdir, 'html', '*'))
- tfiles = filter(os.path.isfile, tfiles)
- installdatafiles.append(
- ('share/roundup/templates/%s/html' % template, tfiles)
- )
+ for idir in '. detectors html'.split():
+ idir = os.path.join(tdir, idir)
+ tfiles = []
+ for f in os.listdir(idir):
+ if f.startswith('.'):
+ continue
+ ifile = os.path.join(idir, f)
+ if os.path.isfile(ifile):
+ tfiles.append(ifile)
+ installdatafiles.append(
+ (os.path.join('share', 'roundup', idir), tfiles)
+ )
# perform the setup action
from roundup import __version__
if error.errno != errno.ENOENT:
raise
from roundup import init, instance, password
- init.install(home, 'classic')
+ init.install(home, os.path.join('templates', 'classic'))
# don't have email flying around
os.remove(os.path.join(home, 'detectors', 'nosyreaction.py'))
init.write_select_db(home, 'anydbm')
diff --git a/templates/classic/.cvsignore b/templates/classic/.cvsignore
--- /dev/null
@@ -0,0 +1,4 @@
+*.pyc
+*.pyo
+htmlbase.py
+*.cover
diff --git a/templates/classic/TEMPLATE-INFO.txt b/templates/classic/TEMPLATE-INFO.txt
--- /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/templates/classic/__init__.py b/templates/classic/__init__.py
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# 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: __init__.py,v 1.1 2003-04-17 03:26:03 richard Exp $
+
+import config
+from dbinit import open, init
+from interfaces import Client, MailGW
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/config.py b/templates/classic/config.py
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# 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: config.py,v 1.1 2003-04-17 03:26:03 richard Exp $
+
+import os
+
+# roundup home is this package's directory
+TRACKER_HOME=os.path.split(__file__)[0]
+
+# The SMTP mail host that roundup will use to send mail
+MAILHOST = 'localhost'
+
+# The domain name used for email addresses.
+MAIL_DOMAIN = 'your.tracker.email.domain.example'
+
+# This is the directory that the database is going to be stored in
+DATABASE = os.path.join(TRACKER_HOME, 'db')
+
+# This is the directory that the HTML templates reside in
+TEMPLATES = os.path.join(TRACKER_HOME, 'html')
+
+# A descriptive name for your roundup instance
+TRACKER_NAME = 'Roundup issue tracker'
+
+# The email address that mail to roundup should go to
+TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
+
+# The web address that the tracker is viewable at. This will be included in
+# information sent to users of the tracker. The URL MUST include the cgi-bin
+# part or anything else that is required to get to the home page of the
+# tracker. You MUST include a trailing '/' in the URL.
+TRACKER_WEB = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/'
+
+# The email address that roundup will complain to if it runs into trouble
+ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
+
+# Additional text to include in the "name" part of the From: address used
+# in nosy messages. If the sending user is "Foo Bar", the From: line is
+# usually:
+# "Foo Bar" <issue_tracker@tracker.example>
+# the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
+# "Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>
+EMAIL_FROM_TAG = ""
+
+# Send nosy messages to the author of the message
+MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no'
+
+# Does the author of a message get placed on the nosy list automatically?
+# If 'new' is used, then the author will only be added when a message
+# creates a new issue. If 'yes', then the author will be added on followups
+# too. If 'no', they're never added to the nosy.
+ADD_AUTHOR_TO_NOSY = 'new' # one of 'yes', 'no', 'new'
+
+# Do the recipients (To:, Cc:) of a message get placed on the nosy list?
+# If 'new' is used, then the recipients will only be added when a message
+# creates a new issue. If 'yes', then the recipients will be added on followups
+# too. If 'no', they're never added to the nosy.
+ADD_RECIPIENTS_TO_NOSY = 'new' # either 'yes', 'no', 'new'
+
+# Where to place the email signature
+EMAIL_SIGNATURE_POSITION = 'bottom' # one of 'top', 'bottom', 'none'
+
+# Keep email citations when accepting messages. Setting this to "no" strips
+# out "quoted" text from the message. Signatures are also stripped.
+EMAIL_KEEP_QUOTED_TEXT = 'yes' # either 'yes' or 'no'
+
+# Preserve the email body as is - that is, keep the citations _and_
+# signatures.
+EMAIL_LEAVE_BODY_UNCHANGED = 'no' # either 'yes' or 'no'
+
+# Default class to use in the mailgw if one isn't supplied in email
+# subjects. To disable, comment out the variable below or leave it blank.
+# Examples:
+MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default
+#MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out)
+
+#
+# SECURITY DEFINITIONS
+#
+# define the Roles that a user gets when they register with the tracker
+# these are a comma-separated string of role names (e.g. 'Admin,User')
+NEW_WEB_USER_ROLES = 'User'
+NEW_EMAIL_USER_ROLES = 'User'
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/dbinit.py b/templates/classic/dbinit.py
--- /dev/null
@@ -0,0 +1,203 @@
+#
+# 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: dbinit.py,v 1.1 2003-04-17 03:26:03 richard Exp $
+
+import os
+
+import config
+from select_db import Database, Class, FileClass, IssueClass
+
+def open(name=None):
+ ''' as from the roundupdb method openDB
+ '''
+ from roundup.hyperdb import String, Password, Date, Link, Multilink
+ from roundup.hyperdb import Interval, Boolean, Number
+
+ # open the database
+ db = Database(config, name)
+
+ #
+ # Now initialise the schema. Must do this each time the database is
+ # opened.
+ #
+
+ # Class automatically gets these properties:
+ # creation = Date()
+ # activity = Date()
+ # creator = Link('user')
+ pri = Class(db, "priority",
+ name=String(), order=String())
+ pri.setkey("name")
+
+ stat = Class(db, "status",
+ name=String(), order=String())
+ stat.setkey("name")
+
+ keyword = Class(db, "keyword",
+ name=String())
+ keyword.setkey("name")
+
+ query = Class(db, "query",
+ klass=String(), name=String(),
+ url=String())
+ query.setkey("name")
+
+ # add any additional database schema configuration here
+
+ # Note: roles is a comma-separated string of Role names
+ user = Class(db, "user",
+ username=String(), password=Password(),
+ address=String(), realname=String(),
+ phone=String(), organisation=String(),
+ alternate_addresses=String(),
+ queries=Multilink('query'), roles=String(),
+ timezone=String())
+ user.setkey("username")
+
+ # FileClass automatically gets these properties:
+ # content = String() [saved to disk in <tracker home>/db/files/]
+ # (it also gets the Class properties creation, activity and creator)
+ 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(), type=String())
+
+ # IssueClass automatically gets these properties:
+ # title = String()
+ # messages = Multilink("msg")
+ # files = Multilink("file")
+ # nosy = Multilink("user")
+ # superseder = Multilink("issue")
+ # (it also gets the Class properties creation, activity and creator)
+ issue = IssueClass(db, "issue",
+ assignedto=Link("user"), topic=Multilink("keyword"),
+ priority=Link("priority"), status=Link("status"))
+
+ #
+ # SECURITY SETTINGS
+ #
+ # See the configuration and customisation document for information
+ # about security setup.
+ # Add new Permissions for this schema
+ for cl in 'issue', 'file', 'msg', 'user', 'query', 'keyword':
+ db.security.addPermission(name="Edit", klass=cl,
+ description="User is allowed to edit "+cl)
+ db.security.addPermission(name="View", klass=cl,
+ description="User is allowed to access "+cl)
+
+ # Assign the access and edit Permissions for issue, file and message
+ # to regular users now
+ for cl in 'issue', 'file', 'msg', 'query', 'keyword':
+ p = db.security.getPermission('View', cl)
+ db.security.addPermissionToRole('User', p)
+ p = db.security.getPermission('Edit', cl)
+ db.security.addPermissionToRole('User', p)
+
+ # and give the regular users access to the web and email interface
+ p = db.security.getPermission('Web Access')
+ db.security.addPermissionToRole('User', p)
+ p = db.security.getPermission('Email Access')
+ db.security.addPermissionToRole('User', p)
+
+ # May users view other user information? Comment these lines out
+ # if you don't want them to
+ p = db.security.getPermission('View', 'user')
+ db.security.addPermissionToRole('User', p)
+
+ # Assign the appropriate permissions to the anonymous user's Anonymous
+ # Role. Choices here are:
+ # - Allow anonymous users to register through the web
+ p = db.security.getPermission('Web Registration')
+ db.security.addPermissionToRole('Anonymous', p)
+ # - Allow anonymous (new) users to register through the email gateway
+ p = db.security.getPermission('Email Registration')
+ db.security.addPermissionToRole('Anonymous', p)
+ # - Allow anonymous users access to the "issue" class of data
+ # Note: this also grants access to related information like files,
+ # messages, statuses etc that are linked to issues
+ p = db.security.getPermission('View', 'issue')
+ db.security.addPermissionToRole('Anonymous', p)
+ # - Allow anonymous users access to edit the "issue" class of data
+ # Note: this also grants access to create related information like
+ # files and messages etc that are linked to issues
+ #p = db.security.getPermission('Edit', 'issue')
+ #db.security.addPermissionToRole('Anonymous', p)
+
+ # oh, g'wan, let anonymous access the web interface too
+ p = db.security.getPermission('Web Access')
+ db.security.addPermissionToRole('Anonymous', p)
+
+ import detectors
+ detectors.init(db)
+
+ # schema is set up - run any post-initialisation
+ db.post_init()
+ return db
+
+def init(adminpw):
+ ''' as from the roundupdb method initDB
+
+ Open the new database, and add new nodes - used for initialisation. You
+ can edit this before running the "roundup-admin initialise" command to
+ change the initial database entries.
+ '''
+ dbdir = os.path.join(config.DATABASE, 'files')
+ if not os.path.isdir(dbdir):
+ os.makedirs(dbdir)
+
+ db = open("admin")
+ db.clear()
+
+ #
+ # 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=config.ADMIN_EMAIL, roles='Admin')
+ user.create(username="anonymous", roles='Anonymous')
+
+ # add any additional database create steps here - but only if you
+ # haven't initialised the database with the admin "initialise" command
+
+ db.commit()
+
+# vim: set filetype=python ts=4 sw=4 et si
+
diff --git a/templates/classic/detectors/.cvsignore b/templates/classic/detectors/.cvsignore
--- /dev/null
@@ -0,0 +1,3 @@
+*.pyc
+*.pyo
+*.cover
diff --git a/templates/classic/detectors/__init__.py b/templates/classic/detectors/__init__.py
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# 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: __init__.py,v 1.1 2003-04-17 03:26:38 richard Exp $
+
+import sys, os, imp
+
+def init(db):
+ ''' execute the init functions of all the modules in this directory
+ '''
+ this_dir = os.path.split(__file__)[0]
+ for file in os.listdir(this_dir):
+ path = os.path.join(this_dir, file)
+ name, ext = os.path.splitext(file)
+ if name == '__init__':
+ continue
+ if ext == '.py':
+ module = imp.load_module(name, open(path), file,
+ ('.py', 'r', imp.PY_SOURCE))
+ module.init(db)
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/detectors/messagesummary.py b/templates/classic/detectors/messagesummary.py
--- /dev/null
@@ -0,0 +1,19 @@
+#$Id: messagesummary.py,v 1.1 2003-04-17 03:26:38 richard 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'], 1, 1)
+ 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
--- /dev/null
@@ -0,0 +1,142 @@
+#
+# 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.1 2003-04-17 03:26:38 richard Exp $
+
+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 = {}
+ 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:
+ if not current.has_key(value):
+ current[value] = 1
+
+ # 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
+ if not current.has_key(value):
+ current[value] = 1
+
+ # 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:
+ if not current.has_key(assignedto_id):
+ current[assignedto_id] = 1
+
+ # 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
+ # there before - make sure we don't get a cached version!
+ oldmessages = cl.get(nodeid, 'messages', cache=0)
+ 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')
+ current[authid] = 1
+
+ # add on the recipients of the message
+ if add_recips in ok:
+ for recipient in msg.get(msgid, 'recipients'):
+ current[recipient] = 1
+
+ # that's it, save off the new nosy list
+ newvalues['nosy'] = current.keys()
+
+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
--- /dev/null
@@ -0,0 +1,78 @@
+# 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.1 2003-04-17 03:26:38 richard Exp $
+
+def chatty(db, cl, nodeid, newvalues):
+ ''' If the issue is currently 'unread', 'resolved' or 'done-cbb', 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', cache=0):
+ 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') and newvalues['status'] != current_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:
+ # 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
+
+ # ok, do it
+ newvalues['status'] = db.status.lookup('unread')
+
+
+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/html/_generic.help.html b/templates/classic/html/_generic.help.html
--- /dev/null
@@ -0,0 +1,91 @@
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="_file/style.css">
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
+<script language="JavaScript"
+ tal:condition="python:request.form.has_key('property')"
+ tal:content="structure string:
+
+// this is the name of the field in the original form that we're working on
+field = '${request/form/property/value}';
+
+function listClose() {
+ window.close();
+}
+
+function listClear() {
+ window.opener.document.itemSynopsis[field].value = '';
+}
+
+function pick(opt) {
+ if (window.opener && !window.opener.closed) {
+ window.opener.document.itemSynopsis[field].value = opt;
+ }
+}
+
+// add a value to the form field
+function add(opt) {
+ val = window.opener.document.itemSynopsis[field].value;
+ if (/^\s*$$/.test(val)) {
+ newval = opt; // existing is all whitespace, so just replace
+ } else {
+ newval = val + ', ' + opt;
+ }
+ pick(newval);
+}
+
+// remove a value from the form field
+function remove(opt) {
+ // ((opt(,\s*)?)|(,\s*opt))
+ replaceStr = new String('(('+opt+'(,\\s*)?)|(,\\s*'+opt+'))');
+ re = new RegExp(replaceStr);
+
+ str = window.opener.document.itemSynopsis[field].value;
+
+ // replace occurences with empty string
+ newstr = str.replace(re, '');
+ pick(newstr);
+}
+">
+</script>
+</head>
+
+<body class="body" marginwidth="0" marginheight="0">
+<form>
+<div style="padding:10px;text-align:center;">
+ <script language="javascript">
+ // put up a 'reset' button if the field has values when we pop up this window
+
+ // this is the name of the field in the original form that we're working on
+ orig = window.opener.document.itemSynopsis[field].value;
+ if (/[^\s]/.test(orig)) {
+ reset = '<input type="button" onclick="pick(orig);" ' +
+ 'value="Reset to original values" /> | ';
+ document.write(reset);
+ }
+ </script>
+ <input type="button"
+ tal:attributes="value string:Clear all ${request/form/property/value} values"
+ onclick="listClear();" /> |
+ <input type="button" onclick="listClose();" value="Close this window" />
+</div>
+
+<table class="classhelp"
+ tal:define="props python:request.form['properties'].value.split(',')">
+<tr>
+ <th tal:condition="python:request.form.has_key('property')">add/remove</th>
+ <th tal:repeat="prop props" tal:content="prop"></th>
+</tr>
+<tr tal:repeat="item context/list">
+ <td tal:condition="python:request.form.has_key('property')">
+ <input type="button" tal:define="opt python: item[props[0]]"
+ tal:attributes="onclick string:add('${opt}')" value=" + ">
+ <input type="button" tal:define="opt python: item[props[0]]"
+ tal:attributes="onclick string:remove('${opt}')" value=" - " />
+ </td>
+ <td tal:repeat="prop props" tal:content="structure python:item[prop]"></td>
+</tr>
+</table>
+</form>
+</body>
+</html>
diff --git a/templates/classic/html/_generic.index.html b/templates/classic/html/_generic.index.html
--- /dev/null
@@ -0,0 +1,48 @@
+<!-- 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"
+ tal:content="python:context._classname.capitalize()+' editing'"></title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<tal:block tal:condition="context/is_edit_ok">
+<p class="form-help">
+ You may edit the contents of the <span tal:replace="request/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>
+
+<form onSubmit="return submit_once()" method="POST">
+<textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea>
+<br>
+<input type="hidden" name=":action" value="editCSV">
+<input type="submit" value="Edit Items">
+</form>
+</tal:block>
+
+<tal:block tal:condition="context/is_only_view_ok">
+view ok
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/_generic.item.html b/templates/classic/html/_generic.item.html
--- /dev/null
@@ -0,0 +1,56 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title"
+ tal:content="python:context._classname.capitalize()+' editing'"></title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<form method="POST" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<input type="hidden" name=":template" value="item">
+<input type="hidden" name=":required" value="title">
+
+<table class="form">
+
+<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>
+<tr>
+ <td> </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/classic/html/file.index.html b/templates/classic/html/file.index.html
--- /dev/null
@@ -0,0 +1,30 @@
+<!-- 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">
+ <span tal:replace="config/TRACKER_NAME" />: List of files
+</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>List of files</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<table class="otherinfo">
+<tr><th style="padding-right: 10">Download</th>
+ <th style="padding-right: 10">Content Type</th>
+ <th style="padding-right: 10">Uploaded By</th>
+ <th style="padding-right: 10">Date</th>
+</tr>
+<tr tal:repeat="file context/list">
+ <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>
+</table>
+
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/file.item.html b/templates/classic/html/file.item.html
--- /dev/null
@@ -0,0 +1,58 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">File display</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>File display</h2>
+</td>
+
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<form method="POST" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<input type="hidden" name=":template" value="item">
+<input type="hidden" name=":required" value="name,type">
+
+<input type="hidden" name=":multilink"
+ tal:condition="python:request.form.has_key(':multilink')"
+ tal:attributes="value request/form/:multilink/value">
+
+<table class="form">
+ <tr>
+ <th>Name</th>
+ <td tal:content="structure context/name/field"></td>
+ </tr>
+ <tr>
+ <th>Content Type</th>
+ <td tal:content="structure context/type/field"></td>
+ </tr>
+
+ <tr>
+ <td> </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}">download</a>
+
+<table class="form" tal:condition="context/is_only_view_ok">
+ <tr>
+ <th>Name</th>
+ <td tal:content="context/name"></td>
+ </tr>
+ <tr>
+ <th>Content Type</th>
+ <td tal:content="context/type"></td>
+ </tr>
+</table>
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()"
+ tal:replace="structure context/history" />
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/home.classlist.html b/templates/classic/html/home.classlist.html
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">List of classes</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>List of classes</h2>
+</td>
+<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
--- /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/templates/classic/html/issue.index.html b/templates/classic/html/issue.index.html
--- /dev/null
@@ -0,0 +1,111 @@
+<!-- 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">
+ <span tal:replace="config/TRACKER_NAME" />: List of issues
+</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>List of issues</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<tal:block tal:condition="not:context/is_view_ok">
+You are not allowed to view this page.
+</tal:block>
+
+<tal:block tal:define="batch request/batch" tal:condition="context/is_view_ok">
+ <table class="list">
+ <tr>
+ <th tal:condition="request/show/priority">Priority</th>
+ <th tal:condition="request/show/id">ID</th>
+ <th tal:condition="request/show/creation">Creation</th>
+ <th tal:condition="request/show/activity">Activity</th>
+ <th tal:condition="request/show/topic">Topic</th>
+ <th tal:condition="request/show/title">Title</th>
+ <th tal:condition="request/show/status">Status</th>
+ <th tal:condition="request/show/creator">Created By</th>
+ <th tal:condition="request/show/assignedto">Assigned To</th>
+ </tr>
+ <tal:block tal:repeat="i batch">
+ <tr tal:condition="python:request.group[1] and
+ batch.propchanged(request.group[1])">
+ <th tal:attributes="colspan python:len(request.columns)"
+ tal:content="python:i[request.group[1]]" class="group">
+ </th>
+ </tr>
+ <tr tal:attributes="class python:['normal', 'alt'][repeat['i'].index%6/3]">
+ <td tal:condition="request/show/priority" tal:content="i/priority"></td>
+ <td tal:condition="request/show/id" tal:content="i/id"></td>
+ <td nowrap tal:condition="request/show/creation"
+ tal:content="i/creation/reldate"></td>
+ <td nowrap tal:condition="request/show/activity"
+ tal:content="i/activity/reldate"></td>
+ <td tal:condition="request/show/topic" tal:content="i/topic"></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" tal:content="i/status"></td>
+ <td tal:condition="request/show/creator" tal:content="i/creator"></td>
+ <td tal:condition="request/show/assignedto" tal:content="i/assignedto"></td>
+ </tr>
+ </tal:block>
+ <tr class="navigation" tal:define="colspan python:len(request.columns)">
+ <th tal:attributes="colspan python:colspan/2">
+ <a tal:define="prev batch/previous" tal:condition="prev"
+ tal:attributes="href python:request.indexargs_url(request.classname,
+ {':startwith':prev.first, ':pagesize':prev.size})"><< previous</a>
+
+ </th>
+ <th tal:attributes="colspan python:colspan/2 + colspan%2">
+ <a tal:define="next batch/next" tal:condition="next"
+ tal:attributes="href python:request.indexargs_url(request.classname,
+ {':startwith':next.first, ':pagesize':next.size})">next >></a>
+
+ </th>
+ </tr>
+</table>
+
+<form method="GET" tal:attributes="action request/classname">
+ <tal:block tal:replace="structure python:request.indexargs_form(sort=0, group=0)" />
+ <table class="form">
+ <tr tal:condition="batch">
+ <th>Sort on:</th>
+ <td>
+ <select name=":sort">
+ <option value="">- nothing -</option>
+ <option tal:repeat="col context/properties"
+ tal:attributes="value col/_name;
+ selected python:col._name == request.sort[1]"
+ tal:content="col/_name">column</option>
+ </select>
+ </td>
+ <th>Descending:</th>
+ <td><input type="checkbox" name=":sortdir"
+ tal:attributes="checked python:request.sort[0] == '-'">
+ </td>
+ </tr>
+ <tr>
+ <th>Group on:</th>
+ <td>
+ <select name=":group">
+ <option value="">- nothing -</option>
+ <option tal:repeat="col context/properties"
+ tal:attributes="value col/_name;
+ selected python:col._name == request.group[1]"
+ tal:content="col/_name">column</option>
+ </select>
+ </td>
+ <th>Descending:</th>
+ <td><input type="checkbox" name=":groupdir"
+ tal:attributes="checked python:request.group[0] == '-'">
+ </td>
+ </tr>
+ <tr><td colspan="4"><input type="submit" value="Redisplay"></td></tr>
+ </table>
+</form>
+
+</tal:block>
+
+</td>
+</tal:block>
+
diff --git a/templates/classic/html/issue.item.html b/templates/classic/html/issue.item.html
--- /dev/null
@@ -0,0 +1,174 @@
+<!-- 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">
+<span tal:replace="config/TRACKER_NAME" />:
+<span tal:condition="context/id"
+ tal:replace="string:Issue ${context/id}: ${context/title}" />
+<tal:x tal:condition="not:context/id">New Issue</tal:x>
+</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>
+ Issue<span tal:replace="context/id" />
+ <tal:x tal:condition="context/is_edit_ok">Editing</tal:x>
+ </h2>
+</td>
+
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<form method="POST" name="itemSynopsis" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<input type="hidden" name=":template" value="item">
+<input type="hidden" name=":required" value="title,priority">
+
+<table class="form">
+<tr>
+ <th class="required" nowrap>Title</th>
+ <td colspan=3 tal:content="structure python:context.title.field(size=60)">title</td>
+</tr>
+
+<tr>
+ <th class="required" nowrap>Priority</th>
+ <td tal:content="structure context/priority/menu">priority</td>
+ <th nowrap>Status</th>
+ <td tal:content="structure context/status/menu">status</td>
+</tr>
+
+<tr>
+ <th nowrap>Superseder</th>
+ <td>
+ <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
+ <span tal:replace="structure python:db.issue.classhelp('id,title', property='superseder')" />
+ <span tal:condition="context/superseder" tal:repeat="sup context/superseder">
+ <br>View: <a tal:attributes="href string:issue${sup/id}"
+ tal:content="sup/id"></a>
+ </span>
+ </td>
+ <th nowrap>Nosy List</th>
+ <td>
+ <span tal:replace="structure context/nosy/field" />
+ <span tal:replace="structure
+python:db.user.classhelp('username,realname,address', property='nosy', width='600')" /><br>
+ </td>
+</tr>
+
+<tr>
+ <th nowrap>Assigned To</th>
+ <td tal:content="structure context/assignedto/menu">assignedto menu</td>
+ <th nowrap>Topics</th>
+ <td>
+ <span tal:replace="structure context/topic/field" />
+ <span tal:replace="structure python:db.keyword.classhelp(property='topic')" />
+ </td>
+</tr>
+
+<tr>
+ <th nowrap>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>
+ <th nowrap>File</th>
+ <td colspan=3><input type="file" name=":file" size="40"></td>
+</tr>
+
+<tr>
+ <td> </td>
+ <td colspan=3 tal:content="structure context/submit">
+ submit button will go here
+ </td>
+</tr>
+</table>
+</form>
+
+<table class="form" tal:condition="not:context/id">
+<tr>
+ <td>Note: </td>
+ <th class="required">highlighted</th>
+ <td> fields are required.</td>
+</tr>
+</table>
+
+<table class="form" tal:condition="context/is_only_view_ok">
+<tr>
+ <th nowrap>Title</th><td colspan=3 tal:content="context/title">title</td>
+</tr>
+
+<tr>
+ <th nowrap>Priority</th><td tal:content="context/priority">priority</td>
+ <th nowrap>Status</th><td tal:content="context/status">status</td>
+</tr>
+
+<tr>
+ <th nowrap>Superseder</th>
+ <td>
+ <span tal:condition="context/superseder" tal:repeat="sup context/superseder">
+ <br>View: <a tal:attributes="href string:issue${sup/id}"
+ tal:content="sup/id"></a>
+ </span>
+ </td>
+ <th nowrap>Nosy List</th><td><span tal:replace="context/nosy" /></td>
+</tr>
+
+<tr>
+ <th nowrap>Assigned To</th><td tal:content="context/assignedto"></td>
+ <th nowrap>Topics</th><td tal:content="structure context/topic"></td>
+</tr>
+</table>
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()">
+
+ <p tal:content="structure string:Created on
+ <b>${context/creation}</b> by <b>${context/creator}</b>, last
+ changed <b>${context/activity}</b>.">activity info
+ </p>
+
+ <table class="messages" tal:condition="context/messages">
+ <tr><th colspan="4" class="header">Messages</th></tr>
+ <tal:block tal:repeat="msg context/messages/reverse">
+ <tr>
+ <th><a tal:attributes="href string:msg${msg/id}"
+ tal:content="string:msg${msg/id}"></a></th>
+ <th tal:content="string:Author: ${msg/author}">author</th>
+ <th tal:content="string:Date: ${msg/date}">date</th>
+ <th>
+ <a tal:attributes="href string:?:remove:messages=${msg/id}&:action=edit">remove</a>
+ </th>
+ </tr>
+ <tr>
+ <td colspan="4" class="content">
+ <pre tal:content="msg/content">content</pre>
+ </td>
+ </tr>
+ </tal:block>
+ </table>
+
+ <table class="files" tal:condition="context/files">
+ <tr><th colspan="2" class="header">Files</th></tr>
+ <tr><th>File name</th><th>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" />
+
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/issue.search.html b/templates/classic/html/issue.search.html
--- /dev/null
@@ -0,0 +1,192 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">Issue searching</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>Issue searching</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<form method="GET" tal:attributes="action request/classname">
+<input type="hidden" name=":action" value="search">
+
+<table class="form" tal:define="
+ cols python:'id activity priority title status assignedto'.split();
+ defsort python:['activity'];
+ defgroup python:['priority'];
+ defdisp python:'id activity title status assignedto'.split()">
+
+<tr>
+ <th class="header"> </th>
+ <th class="header">Filter on</th>
+ <th class="header">Display</th>
+ <th class="header">Sort on</th>
+ <th class="header">Group on</th>
+</tr>
+
+<tr>
+ <th>All text*:</th>
+ <td><input name=":search_text"
+ tal:attributes="value request/form/:search_text/value | nothing">
+ </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+</tr>
+
+<tr>
+ <th>Title:</th>
+ <td><input name="title"></td>
+ <td><input type="checkbox" name=":columns" value="title" checked></td>
+ <td><input type="radio" name=":sort" value="title"></td>
+ <td> </td>
+</tr>
+
+<tr>
+ <th>Topic:</th>
+ <td>
+ <select name="topic">
+ <option value="">don't care</option>
+ <option value="">------------</option>
+ <option tal:repeat="s db/keyword/list" tal:attributes="value s/name"
+ tal:content="s/name">topic to filter on</option>
+ </select>
+ </td>
+ <td><input type="checkbox" name=":columns" value="topic" checked></td>
+ <td><input type="radio" name=":sort" value="topic"></td>
+ <td><input type="radio" name=":group" value="topic"></td>
+</tr>
+
+<tr>
+ <th>ID:</th>
+ <td><input name="id"></td>
+ <td><input type="checkbox" name=":columns" value="id" checked></td>
+ <td><input type="radio" name=":sort" value="id"></td>
+ <td> </td>
+</tr>
+
+<tr>
+ <th>Creation date:</th>
+ <td><input name="creation"></td>
+ <td><input type="checkbox" name=":columns" value="creation"></td>
+ <td><input type="radio" name=":sort" value="creation"></td>
+ <td><input type="radio" name=":group" value="creation"></td>
+</tr>
+
+<tr>
+ <th>Creator:</th>
+ <td>
+ <select name="creator">
+ <option value="">don't care</option>
+ <option tal:attributes="value request/user/id">created by me</option>
+ <option value="-1">------------</option>
+ <option tal:repeat="s db/user/list" tal:attributes="value s/id"
+ tal:content="s/username">user to filter on</option>
+ </select>
+ </td>
+ <td><input type="checkbox" name=":columns" value="creator" checked></td>
+ <td><input type="radio" name=":sort" value="creator"></td>
+ <td><input type="radio" name=":group" value="creator"></td>
+</tr>
+
+<tr>
+ <th>Activity:</th>
+ <td><input name="activity"></td>
+ <td><input type="checkbox" name=":columns" value="activity" checked></td>
+ <td><input type="radio" name=":sort" value="activity"></td>
+ <td> </td>
+</tr>
+
+<tr>
+ <th>Priority:</th>
+ <td>
+ <select name="priority">
+ <option value="">don't care</option>
+ <option value="-1">not selected</option>
+ <option value="">------------</option>
+ <option tal:repeat="s db/priority/list" tal:attributes="value s/id"
+ tal:content="s/name">priority to filter on</option>
+ </select>
+ </td>
+ <td><input type="checkbox" name=":columns" value="priority"></td>
+ <td><input type="radio" name=":sort" value="priority"></td>
+ <td><input type="radio" name=":group" value="priority"></td>
+</tr>
+
+<tr>
+ <th>Status:</th>
+ <td>
+ <select name="status">
+ <option value="">don't care</option>
+ <option value="-1,1,2,3,4,5,6,7">not resolved</option>
+ <option value="-1">not selected</option>
+ <option value="">------------</option>
+ <option tal:repeat="s db/status/list" tal:attributes="value s/id"
+ tal:content="s/name">status to filter on</option>
+ </select>
+ </td>
+ <td><input type="checkbox" name=":columns" value="status" checked></td>
+ <td><input type="radio" name=":sort" value="status"></td>
+ <td><input type="radio" name=":group" value="status"></td>
+</tr>
+
+<tr>
+ <th>Assigned To:</th>
+ <td>
+ <select name="assignedto">
+ <option value="">don't care</option>
+ <option tal:attributes="value request/user/id">assigned to me</option>
+ <option value="-1">unassigned</option>
+ <option value="">------------</option>
+ <option tal:repeat="s db/user/list" tal:attributes="value s/id"
+ tal:content="s/username">user to filter on</option>
+ </select>
+ </td>
+ <td><input type="checkbox" name=":columns" value="assignedto" checked></td>
+ <td><input type="radio" name=":sort" value="assignedto"></td>
+ <td><input type="radio" name=":group" value="assignedto"></td>
+</tr>
+
+<tr>
+<th>Pagesize:</th>
+<td><input type="text" name=":pagesize" size="3" value="50"></td>
+</tr>
+
+<tr>
+<th>Start With:</th>
+<td><input type="text" name=":startwith" size="3" value="0"></td>
+</tr>
+
+<tr>
+<th>Sort Descending:</th>
+<td><input type="checkbox" name=":sortdir" checked>
+</td>
+
+<tr>
+<th>Group Descending:</th>
+<td><input type="checkbox" name=":groupdir">
+</td>
+</tr>
+
+<tr>
+<th>Query name**:</th>
+<td><input name=":queryname"
+ tal:attributes="value request/form/:queryname/value | nothing">
+</td>
+</tr>
+
+<tr><td> </td>
+<td><input type="submit" value="Search"></td>
+</tr>
+
+<tr><td> </td>
+ <td colspan="4" class="help">
+ *: The "all text" field will look in message bodies and issue titles<br>
+ **: If you supply a name, the query will be saved off and available as a
+ link in the sidebar
+ </td>
+</tr>
+</table>
+
+</form>
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/keyword.item.html b/templates/classic/html/keyword.item.html
--- /dev/null
@@ -0,0 +1,53 @@
+<!-- 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">Keyword editing</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>Keyword editing</h2>
+</td>
+<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">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">
+ 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">
+ 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">
+
+ <input type="hidden" name=":required" value="name">
+ <input type="hidden" name=":template" value="item">
+
+ <table class="form">
+ <tr>
+ <th nowrap>Keyword</th>
+ <td tal:content="structure context/name/field">name</td>
+ </tr>
+
+ <tr>
+ <td> </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
--- /dev/null
@@ -0,0 +1,23 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">
+ <span tal:replace="config/TRACKER_NAME" />: List of messages
+</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>Message listing</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+<table class="messages" tal:condition="request/filter">
+ <tr><th colspan=2 class="header">Messages</th></tr>
+ <tal:block tal:repeat="msg context/list">
+ <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>
+</table>
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/msg.item.html b/templates/classic/html/msg.item.html
--- /dev/null
@@ -0,0 +1,58 @@
+<!-- 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">
+<span tal:replace="config/TRACKER_NAME" />:
+<span tal:condition="context/id" tal:replace="string:Message ${context/id}" />
+<tal:x tal:condition="not:context/id">New Message</tal:x>
+</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>
+ Message<span tal:replace="context/id" />
+ <tal:x tal:condition="context/is_edit_ok">Editing</tal:x>
+ </h2>
+</td>
+<td class="content" metal:fill-slot="content">
+<table class="form">
+
+<tr>
+ <th nowrap>Author</th>
+ <td tal:content="context/author"></td>
+</tr>
+
+<tr>
+ <th nowrap>Recipients</th>
+ <td tal:content="context/recipients"></td>
+</tr>
+
+<tr>
+ <th nowrap>Date</th>
+ <td tal:content="context/date"></td>
+</tr>
+</table>
+
+<table class="messages">
+ <tr><th colspan=2 class="header">Content</th></tr>
+ <tr>
+ <td class="content" colspan=2><pre tal:content="context/content"></pre></td>
+ </tr>
+</table>
+
+<table class="files" tal:condition="context/files">
+ <tr><th colspan="2" class="header">Files</th></tr>
+ <tr><th>File name</th><th>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" />
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/page.html b/templates/classic/html/page.html
--- /dev/null
@@ -0,0 +1,104 @@
+<html metal:define-macro="icing">
+<head>
+<title metal:define-slot="head_title">title goes here</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
+
+<link rel="stylesheet" type="text/css" href="_file/style.css">
+
+<script tal:replace="structure request/base_javascript">
+</script>
+
+</head>
+<body class="body" marginwidth="0" marginheight="0">
+
+<table class="body">
+
+<tr>
+ <td class="page-header-left"> </td>
+ <td class="page-header-top" metal:define-slot="body_title"><h2>name</h2></td>
+</tr>
+
+<tr>
+ <td rowspan="2" valign="top" nowrap class="sidebar">
+ <p class="classblock" tal:condition="request/user/queries">
+ <b>Your Queries</b><br>
+ <tal:block tal:repeat="qs request/user/queries">
+ <a tal:attributes="href string:${qs/klass}${qs/url}"
+ tal:content="qs/name">link</a><br>
+ </tal:block>
+ </p>
+
+ <form method="POST">
+ <p class="classblock"
+ tal:condition="python:request.user.hasPermission('View', 'issue')">
+ <b>Issues</b><br>
+ <a tal:condition="python:request.user.hasPermission('Edit', 'issue')"
+ href="issue?:template=item">Create New<br></a>
+ <a href="issue?:sort=-activity&:group=priority&:filter=status,assignedto&:columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=-1">Show Unassigned</a><br>
+ <a href="issue?:sort=-activity&:group=priority&:filter=status&:columns=id,activity,title,creator,assignedto,status&status=-1,1,2,3,4,5,6,7">Show All</a><br>
+ <a href="issue?:template=search">Search</a><br>
+ <input type="submit" value="Show issue no."><input 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:request.user.hasPermission('View', 'keyword')">
+ <b>Keywords</b><br>
+ <a tal:condition="python:request.user.hasPermission('Edit', 'keyword')"
+ href="keyword?:template=item">Create New<br></a>
+ <a tal:condition="python:request.user.hasPermission('Edit', 'keyword') and
+ len(db.keyword.list())"
+ href="keyword?:template=item">Edit Existing<br></a>
+ </p>
+
+ <p class="classblock"
+ tal:condition="python:request.user.username != 'anonymous'">
+ <b>Administration</b><br>
+ <a tal:condition="python:request.user.hasPermission('Edit', None)"
+ href="home?:template=classlist">Class List</a><br>
+ <a tal:condition="python:request.user.hasPermission('View', 'user')
+ or request.user.hasPermission('Edit', 'user')"
+ href="user" >User List</a><br>
+ <a tal:condition="python:request.user.hasPermission('Edit', 'user')"
+ href="user?:template=item">Add User</a>
+ </p>
+
+ <form method="POST" action="">
+ <p class="userblock" tal:condition="python:request.user.username=='anonymous'">
+ <input size="10" name="__login_name"><br>
+ <input size="10" type="password" name="__login_password"><br>
+ <input type="submit" name=":action" value="login">
+ <span tal:replace="structure request/indexargs_form" />
+ <a href="user?:template=register">Register</a><br>
+ <a href="user?:template=forgotten">Forgotten your password?</a><br>
+ </p>
+ </form>
+
+ <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
+ <b>Hello,</b><br><b tal:content="request/user/username">username</b><br>
+ <a tal:attributes="href string:issue?:sort=-activity&:group=priority&:filter=status,assignedto&:columns=id,activity,title,creator,status&status=-1,1,2,3,4,5,6,7&assignedto=${request/user/id}">My Issues</a><br>
+ <a tal:attributes="href string:user${request/user/id}">My Details</a><br>
+ <a tal:attributes="href python:request.indexargs_href('',
+ {':action':'logout'})">Logout</a>
+ </p>
+ </td>
+ <td>
+ <p tal:condition="options/error_message | nothing" class="error-message"
+ tal:repeat="m options/error_message" tal:content="structure m">error</p>
+ <p tal:condition="options/ok_message | nothing" class="ok-message"
+ tal:repeat="m options/ok_message" tal:content="structure m">error</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>
diff --git a/templates/classic/html/query.item.html b/templates/classic/html/query.item.html
--- /dev/null
@@ -0,0 +1,3 @@
+<!-- query.item -->
+<span tal:content="structure context/renderQueryForm" />
+
diff --git a/templates/classic/html/style.css b/templates/classic/html/style.css
--- /dev/null
@@ -0,0 +1,308 @@
+/* main page styles */
+body.body {
+ font-family: sans-serif, Arial, Helvetica;
+ color: #333333;
+}
+a[href]:hover { color:blue; text-decoration: underline; }
+a[href]:link { color:blue; text-decoration: none; }
+a[href] { color:blue; text-decoration: none; }
+
+table.body {
+ border: 0;
+ padding: 0;
+ border-spacing: 0px;
+ border-collapse: separate;
+}
+
+td.page-header-left {
+ padding: 5px;
+ border-bottom: 1px solid #444444;
+}
+
+td.page-header-top {
+ padding: 5px;
+ border-bottom: 1px solid #444444;
+}
+
+td.sidebar {
+ padding: 1 0 0 1;
+}
+
+td.sidebar p.classblock {
+ padding: 0 5 0 5;
+ margin: 1 1 1 1;
+ border: 1px solid #444444;
+ background-color: #eeeeee;
+}
+
+td.sidebar p.userblock {
+ padding: 0 5 0 5;
+ margin: 1 1 1 1;
+ border: 1px solid #444444;
+ background-color: #eeeeff;
+}
+
+td.content {
+ padding: 1 5 1 5;
+ vertical-align: top;
+ width: 100%;
+}
+
+p.ok-message {
+ background-color: #22bb22;
+ padding: 5 5 5 5;
+ color: white;
+ font-weight: bold;
+}
+p.error-message {
+ background-color: #bb2222;
+ padding: 5 5 5 5;
+ color: white;
+ font-weight: bold;
+}
+
+
+/* style for forms */
+table.form {
+ padding: 2;
+ border-spacing: 0px;
+ border-collapse: separate;
+}
+
+table.form th {
+ color: #333388;
+ text-align: right;
+ vertical-align: top;
+ font-weight: normal;
+}
+
+table.form th.header {
+ font-weight: bold;
+ background-color: #eeeeff;
+ text-align: left;
+}
+
+table.form th.required {
+ font-weight: bold;
+}
+
+table.form td {
+ color: #333333;
+ empty-cells: show;
+ vertical-align: top;
+}
+
+table.form td.optional {
+ font-weight: bold;
+ font-style: italic;
+}
+
+table.form td.html {
+ color: #777777;
+}
+
+/* style for lists */
+table.list {
+ border-spacing: 0px;
+ border-collapse: separate;
+ width: 100%;
+}
+
+table.list th {
+ padding: 0 4 0 4;
+ color: #404070;
+ background-color: #eeeeff;
+ 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 4 0 4;
+ border: 1px solid white;
+ color: #404070;
+ background-color: white;
+ vertical-align: top;
+ empty-cells: show;
+}
+
+table.list tr.normal td {
+ background-color: #efefef;
+}
+
+table.list tr.alt td {
+ background-color: #efefef;
+}
+
+table.list tr.navigation th {
+ text-align: right;
+}
+table.list tr.navigation th:first-child {
+ text-align: left;
+}
+
+
+/* style for message displays */
+table.messages {
+ border-spacing: 0px;
+ 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: 2 5 2 5;
+}
+
+table.messages td:first-child {
+ border-left: 1px solid #afafaf;
+ border-right: 1px solid #afafaf;
+}
+
+/* style for file displays */
+table.files {
+ border-spacing: 0px;
+ 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: 0px;
+ 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: 0px;
+ 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 {
+ border-spacing: 0px;
+ border-collapse: separate;
+ width: 100%;
+}
+
+table.classhelp th {
+ font-weight: bold;
+ text-align: left;
+ color: #707040;
+}
+
+table.classhelp td {
+ padding: 2 2 2 2;
+ border: 1px solid black;
+ text-align: left;
+ vertical-align: top;
+ empty-cells: show;
+}
+
+
+/* style for "other" displays */
+table.otherinfo {
+ border-spacing: 0px;
+ 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/classic/html/user.forgotten.html b/templates/classic/html/user.forgotten.html
--- /dev/null
@@ -0,0 +1,33 @@
+<!-- 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">Password reset request</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>Password reset request</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<p>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()">
+<input type="hidden" name="@action" value="passrst">
+<input type="hidden" name="@template" value="forgotten">
+<table class="form">
+ <tr><th>Email Address:</th> <td><input name="address"></td> </tr>
+ <tr><td></td><td><input type="submit" value="Request password reset"></td></tr>
+</table>
+
+<p>Or, if you know your username, then enter it below.</p>
+
+<table class="form">
+ <tr><th>Username:</th> <td><input name="username"></td> </tr>
+ <tr><td></td><td><input type="submit" value="Request password reset"></td></tr>
+</table>
+</form>
+
+<p>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.index.html b/templates/classic/html/user.index.html
--- /dev/null
@@ -0,0 +1,40 @@
+<!-- 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">User listing</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>User listing</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="not:context/is_view_ok">
+You are not allowed to view this page.
+</span>
+
+<table width="100%" tal:condition="context/is_view_ok" class="list">
+<tr>
+ <th>Username</th>
+ <th>Real name</th>
+ <th>Organisation</th>
+ <th>Email address</th>
+ <th>Phone number</th>
+ <th tal:condition="context/is_edit_ok">Retire</th>
+</tr>
+<tr tal:repeat="user context/list"
+ 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="user/realname">realname</td>
+ <td tal:content="user/organisation">organisation</td>
+ <td tal:content="python:user.address.email()">address</td>
+ <td tal:content="user/phone">phone</td>
+ <td tal:condition="context/is_edit_ok">
+ <a tal:attributes="href string:user${user/id}?:action=retire&:template=index">
+ retire</a>
+ </td>
+</tr>
+</table>
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/user.item.html b/templates/classic/html/user.item.html
--- /dev/null
@@ -0,0 +1,126 @@
+<!-- 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">
+<span tal:replace="config/TRACKER_NAME" />:
+<span tal:condition="context/id"
+ tal:replace="string:User ${context/id}: ${context/username}" />
+<tal:x tal:condition="not:context/id">New User</tal:x>
+</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>
+ User<span tal:replace="context/id" />
+ <tal:x tal:condition="context/is_edit_ok">Editing</tal:x>
+ </h2>
+</td>
+
+<td class="content" metal:fill-slot="content">
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<form method="POST" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<input type="hidden" name=":required" value="username,address">
+
+<table class="form">
+ <tr>
+ <th>Name</th>
+ <td tal:content="structure context/realname/field">realname</td>
+ </tr>
+ <tr>
+ <th>Login Name</th>
+ <td tal:content="structure context/username/field">username</td>
+ </tr>
+ <tr>
+ <th>Login Password</th>
+ <td tal:content="structure context/password/field">password</td>
+ </tr>
+ <tr>
+ <th>Confirm Password</th>
+ <td tal:content="structure context/password/confirm">password</td>
+ </tr>
+ <tr tal:condition="python:request.user.hasPermission('Web Roles')">
+ <th>Roles</th>
+ <td tal:condition="context/id"
+ tal:content="structure context/roles/field">roles</td>
+ <td tal:condition="not:context/id">
+ <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
+ (to give the user more than one role, enter a comma,separated,list)
+ </td>
+ </tr>
+ <tr>
+ <th>Phone</th>
+ <td tal:content="structure context/phone/field">phone</td>
+ </tr>
+ <tr>
+ <th>Organisation</th>
+ <td tal:content="structure context/organisation/field">organisation</td>
+ </tr>
+ <tr>
+ <th>Timezone</th>
+ <td tal:content="structure context/timezone/field">timezone</td>
+ </tr>
+ <tr>
+ <th>E-mail address</th>
+ <td tal:content="structure context/address/field">address</td>
+ </tr>
+ <tr>
+ <th>Alternate E-mail addresses<br>One address per line</th>
+ <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
+ </tr>
+
+ <tr>
+ <td> </td>
+ <td tal:content="structure context/submit">submit button here</td>
+ </tr>
+</table>
+</form>
+
+<table class="otherinfo" tal:condition="context/queries">
+ <tr><th colspan="3" class="header">Queries</th></tr>
+ <tr><th>Name</th><th colspan="2">Actions</th></tr>
+ <tr tal:repeat="query context/queries">
+ <td><a tal:attributes="href string:query${query/id}"
+ tal:content="query/name"></a></td>
+ <td>
+ <a tal:attributes="href python:'%s%s'%(query['klass'], query['url'])">display</a>
+ </td>
+ <td>
+ <a tal:attributes="href string:?:remove:queries=${query/id}&:action=edit">remove</a>
+ </td>
+ </tr>
+</table>
+
+<table class="form" tal:condition="context/is_only_view_ok">
+ <tr>
+ <th colspan=2 class="header" tal:content="context/realname">realname</th>
+ </tr>
+ <tr>
+ <th>Login Name</th>
+ <td tal:content="context/username">username</td>
+ </tr>
+ <tr>
+ <th>Phone</th>
+ <td tal:content="context/phone">phone</td>
+ </tr>
+ <tr>
+ <th>Organisation</th>
+ <td tal:content="context/organisation">organisation</td>
+ </tr>
+ <tr>
+ <th>Timezone</th>
+ <td tal:content="context/timezone">timezone</td>
+ </tr>
+ <tr>
+ <th>E-mail address</th>
+ <td tal:content="context/address/email">address</td>
+ </tr>
+</table>
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()"
+ tal:replace="structure context/history" />
+
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/user.register.html b/templates/classic/html/user.register.html
--- /dev/null
@@ -0,0 +1,82 @@
+<!-- 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"
+ tal:content="string:Registering with ${db/config/TRACKER_NAME}"></title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2 tal:content="string:Registering with ${db/config/TRACKER_NAME}"></h2>
+</td>
+<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">
+You are not allowed to view this page.
+</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>Name</th>
+ <td tal:content="structure context/realname/field">realname</td>
+ </tr>
+ <tr>
+ <th>Login Name</th>
+ <td tal:content="structure context/username/field">username</td>
+ </tr>
+ <tr>
+ <th>Login Password</th>
+ <td tal:content="structure context/password/field">password</td>
+ </tr>
+ <tr>
+ <th>Confirm Password</th>
+ <td tal:content="structure context/password/confirm">password</td>
+ </tr>
+ <tr tal:condition="python:request.user.hasPermission('Web Roles')">
+ <th>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>Phone</th>
+ <td tal:content="structure context/phone/field">phone</td>
+ </tr>
+ <tr>
+ <th>Organisation</th>
+ <td tal:content="structure context/organisation/field">organisation</td>
+ </tr>
+ <tr>
+ <th>E-mail address</th>
+ <td tal:content="structure context/address/field">address</td>
+ </tr>
+ <tr>
+ <th>Alternate E-mail addresses<br>One address per line</th>
+ <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
+ </tr>
+
+ <tr>
+ <td> </td>
+ <td>
+ <input type="hidden" name=":action" value="register">
+ <input type="submit" name="submit" value="Register">
+ </td>
+ </tr>
+</table>
+</form>
+
+</tal:block>
+
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/templates/classic/html/user.rego_progress.html b/templates/classic/html/user.rego_progress.html
--- /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">List of issues</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h1>Registration in progress...</h1>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<p>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/htmlbase.py b/templates/classic/htmlbase.py
--- /dev/null
@@ -0,0 +1,529 @@
+
+# Do Not Edit (Unless You Want To)
+# This file automagically generated by roundup.templatebuilder.makeHtmlBase
+#
+fileDOTindex = """<!-- dollarId: file.index,v 1.4 2002/01/23 05:10:27 richard Exp dollar-->
+<tr>
+ <property name="name">
+ <td><display call="download('name')"></td>
+ </property>
+ <property name="type">
+ <td><display call="plain('type')"></td>
+ </property>
+ <property name="creator">
+ <td><display call="plain('creator')"></td>
+ </property>
+ <property name="creation">
+ <td><display call="plain('creation')"></td>
+ </property>
+</tr>
+"""
+
+fileDOTnewitem = """<!-- dollarId: file.newitem,v 1.1 2001/07/30 08:12:17 richard Exp dollar-->
+<table border=0 cellspacing=0 cellpadding=2>
+
+<tr class="strong-header">
+ <td colspan=2>File upload details</td>
+</td>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">File:</span></td>
+ <td class="form-text"><input type="file" name="content" size="40"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td> </td>
+ <td class="form-text"><display call="submit()"></td>
+</tr>
+
+</table>
+"""
+
+issueDOTfilter = """<!-- dollarId: issue.filter,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<property name="title">
+ <tr><th width="1%" align="right" class="location-bar">Title</th>
+ <td><display call="field('title')"></td></tr>
+</property>
+<property name="status">
+ <tr><th width="1%" align="right" class="location-bar">Status</th>
+ <td><display call="checklist('status')"></td></tr>
+</property>
+<property name="priority">
+ <tr><th width="1%" align="right" class="location-bar">Priority</th>
+ <td><display call="checklist('priority')"></td></tr>
+</property>
+<property name="assignedto">
+ <tr><th width="1%" align="right" class="location-bar">Assignedto</th>
+ <td><display call="field('assignedto')"></td></tr>
+</property>
+"""
+
+issueDOTindex = """<!-- dollarId: issue.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<tr class="row-<display call="plain('status')">">
+ <property name="id">
+ <td valign="top"><display call="plain('id')"></td>
+ </property>
+ <property name="activity">
+ <td valign="top"><display call="reldate('activity', pretty=1)"></td>
+ </property>
+ <property name="priority">
+ <td valign="top"><display call="plain('priority')"></td>
+ </property>
+ <property name="title">
+ <td valign="top"><display call="link('title')"></td>
+ </property>
+ <property name="status">
+ <td valign="top"><display call="plain('status')"></td>
+ </property>
+ <property name="assignedto">
+ <td valign="top"><display call="link('assignedto')"></td>
+ </property>
+</tr>
+"""
+
+issueDOTitem = """<!-- dollarId: issue.item,v 1.4 2001/08/03 01:19:43 richard Exp dollar-->
+<table border=0 cellspacing=0 cellpadding=2>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Title</span></td>
+ <td colspan=3 class="form-text"><display call="field('title', size=80)"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Created</span></td>
+ <td class="form-text"><display call="reldate('creation', pretty=1)">
+ (<display call="plain('creator')">)</td>
+ <td width=1% nowrap align=right><span class="form-label">Last activity</span></td>
+ <td class="form-text"><display call="reldate('activity', pretty=1)"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Priority</span></td>
+ <td class="form-text"><display call="menu('priority')"></td>
+ <td width=1% nowrap align=right><span class="form-label">Status</span></td>
+ <td class="form-text"><display call="menu('status')"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Superseder</span></td>
+ <td class="form-text"><display call="field('superseder', size=40, showid=1)"></td>
+ <td width=1% nowrap align=right><span class="form-label">Nosy List</span></td>
+ <td class="form-text"><display call="field('nosy')"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Assigned To</span></td>
+ <td class="form-text"><display call="menu('assignedto')"></td>
+ <td> </td>
+ <td> </td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Change Note</span></td>
+ <td colspan=3 class="form-text"><display call="note()"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">File</span></td>
+ <td colspan=3 class="form-text"><input type="file" name="__file" size="80"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td> </td>
+ <td colspan=3 class="form-text"><display call="submit()"></td>
+</tr>
+
+<tr class="msg-header">
+ <td colspan=4><b>Messages</b></td>
+</tr>
+<property name="messages">
+<tr>
+ <td colspan=4><display call="list('messages')"></td>
+</tr>
+</property>
+
+<tr class="file-header">
+ <td colspan=4><b>Files</b></td>
+</tr>
+<tr class="form-help">
+ <td colspan=4>
+ <a href="newfile?:multilink=issue<display
+call="plain('id')">:files">Attach a file to this issue</a>
+ </td>
+</tr>
+<property name="files">
+ <tr>
+ <td colspan=4><display call="list('files')"></td>
+ </tr>
+</property>
+
+<tr class="history-header">
+ <td colspan=4><b>History</b></td>
+</tr>
+<tr>
+ <td colspan=4><display call="history()"></td>
+</tr>
+
+</table>
+
+"""
+
+msgDOTindex = """<!-- dollarId: msg.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<tr>
+ <property name="date">
+ <td><display call="link('date')"></td>
+ </property>
+ <property name="author">
+ <td><display call="plain('author')"></td>
+ </property>
+ <property name="summary">
+ <td><display call="plain('summary')"></td>
+ </property>
+</tr>
+"""
+
+msgDOTitem = """<!-- dollarId: msg.item,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<table border=0 cellspacing=0 cellpadding=2>
+
+<tr class="strong-header">
+ <td colspan=2>Message Information</td>
+</td>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Author</span></td>
+ <td class="form-text"><display call="plain('author')"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Recipients</span></td>
+ <td class="form-text"><display call="plain('recipients')"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Date</span></td>
+ <td class="form-text"><display call="plain('date')"></td>
+</tr>
+
+<tr bgcolor="ffeaff">
+ <td colspan=2 class="form-text">
+ <pre><display call="plain('content')"></pre>
+ </td>
+</tr>
+
+<property name="files">
+<tr class="strong-header"><td colspan=2><b>Files</b></td></tr>
+<tr><td colspan=2><display call="list('files')"></td></tr>
+</property>
+
+<tr class="strong-header"><td colspan=2><b>History</b></td><tr>
+<tr><td colspan=2><display call="history()"></td></tr>
+
+</table>
+"""
+
+styleDOTcss = """h1 {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 18pt;
+ font-weight: bold;
+}
+
+h2 {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 16pt;
+ font-weight: bold;
+}
+
+h3 {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 12pt;
+ font-weight: bold;
+}
+
+a:hover {
+ font-family: Verdana, Helvetica, sans-serif;
+ text-decoration: underline;
+ color: #333333;
+}
+
+a:link {
+ font-family: Verdana, Helvetica, sans-serif;
+ text-decoration: none;
+ color: #000099;
+}
+
+a {
+ font-family: Verdana, Helvetica, sans-serif;
+ text-decoration: none;
+ color: #000099;
+}
+
+p {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+ color: #333333;
+}
+
+th {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-weight: bold;
+ font-size: 10pt;
+ color: #333333;
+}
+
+.form-help {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+ color: #333333;
+}
+
+.std-text {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+ color: #333333;
+}
+
+.tab-small {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 8pt;
+ color: #333333;
+}
+
+.location-bar {
+ background-color: #44bb66;
+ color: #ffffff;
+ border: none;
+}
+
+.strong-header {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 12pt;
+ font-weight: bold;
+ background-color: #000000;
+ color: #ffffff;
+}
+
+.msg-header {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 12pt;
+ font-weight: bold;
+ background-color: #EE71AC;
+ color: #ffffff;
+}
+
+.file-header {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 12pt;
+ font-weight: bold;
+ background-color: #41BE62;
+ color: #ffffff;
+}
+
+.history-header {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 12pt;
+ font-weight: bold;
+ background-color: #739DEE;
+ color: #ffffff;
+}
+
+.list-header {
+ background-color: #aaccff;
+ color: #000000;
+ border: none;
+}
+
+.list-item {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+}
+
+.list-nav {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+ font-weight: bold;
+}
+
+.row-normal {
+ background-color: #ffffff;
+ border: none;
+
+}
+
+.row-hilite {
+ background-color: #efefef;
+ border: none;
+}
+
+.row-unread {
+ background-color: #ffddd9;
+ border: none;
+}
+
+.row-in-progress {
+ background-color: #3ccc50;
+ border: none;
+}
+
+.row-resolved {
+ background-color: #aaccff;
+ border: none;
+}
+
+.row-done-cbb {
+ background-color: #aaccff;
+ border: none;
+}
+
+.row-testing {
+ background-color: #c6ddff;
+ border: none;
+}
+
+.row-need-eg {
+ background-color: #ffc7c0;
+ border: none;
+}
+
+.row-chatting {
+ background-color: #ffe3c0;
+ border: none;
+}
+
+.row-deferred {
+ background-color: #cccccc;
+ border: none;
+}
+
+.section-bar {
+ background-color: #707070;
+ color: #ffffff;
+ border: 1px solid #404040;
+}
+
+.system-msg {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+ background-color: #ffffff;
+ border: 1px solid #000000;
+ margin-bottom: 6px;
+ margin-top: 6px;
+ padding: 4px;
+ width: 100%;
+ color: #660033;
+}
+
+.form-title {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-weight: bold;
+ font-size: 12pt;
+ color: #333333;
+}
+
+.form-label {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-weight: bold;
+ font-size: 10pt;
+ color: #333333;
+}
+
+.form-optional {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-weight: bold;
+ font-style: italic;
+ font-size: 10pt;
+ color: #333333;
+}
+
+.form-element {
+ font-family: Verdana, Helvetica, aans-serif;
+ font-size: 10pt;
+ color: #000000;
+}
+
+.form-text {
+ font-family: Verdana, Helvetica, sans-serif;
+ font-size: 10pt;
+ color: #333333;
+}
+
+.form-mono {
+ font-family: monospace;
+ font-size: 12px;
+ text-decoration: none;
+}
+"""
+
+userDOTindex = """<!-- dollarId: user.index,v 1.2 2001/07/29 04:07:37 richard Exp dollar-->
+<tr>
+ <property name="username">
+ <td><display call="link('username')"></td>
+ </property>
+ <property name="realname">
+ <td><display call="plain('realname')"></td>
+ </property>
+ <property name="organisation">
+ <td><display call="plain('organisation')"></td>
+ </property>
+ <property name="address">
+ <td><display call="plain('address')"></td>
+ </property>
+ <property name="phone">
+ <td><display call="plain('phone')"></td>
+ </property>
+</tr>
+"""
+
+userDOTitem = """<!-- dollarId: user.item,v 1.3 2002/02/15 07:08:44 richard Exp dollar-->
+<table border=0 cellspacing=0 cellpadding=2>
+
+<tr class="strong-header">
+ <td colspan=2>Your Details</td>
+</td>
+
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Name</span></td>
+ <td class="form-text"><display call="field('realname', size=40)"></td>
+</tr>
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Login Name</span></td>
+ <td class="form-text"><display call="field('username', size=40)"></td>
+</tr>
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Login Password</span></td>
+ <td class="form-text"><display call="field('password', size=10)"></td>
+</tr>
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Phone</span></td>
+ <td class="form-text"><display call="field('phone', size=40)"></td>
+</tr>
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Organisation</span></td>
+ <td class="form-text"><display call="field('organisation', size=40)"></td>
+</tr>
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">E-mail address</span></td>
+ <td class="form-text"><display call="field('address', size=40)"></td>
+</tr>
+<tr bgcolor="ffffea">
+ <td width=1% nowrap align=right><span class="form-label">Alternate
+ E-mail addresses</span><br>
+ <span class="form-help">One address per line</span></td>
+ <td class="form-text"><display call="multiline('alternate_addresses')"></td>
+</tr>
+
+<tr bgcolor="ffffea">
+ <td> </td>
+ <td class="form-text"><display call="submit()"></td>
+</tr>
+
+<tr class="strong-header">
+ <td colspan=2><b>History</b></td>
+</tr>
+<tr>
+ <td colspan=2><display call="history()"></td>
+</tr>
+
+</table>
+
+"""
+
diff --git a/templates/classic/interfaces.py b/templates/classic/interfaces.py
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# 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: interfaces.py,v 1.1 2003-04-17 03:26:03 richard Exp $
+
+from roundup import mailgw
+from roundup.cgi import client
+
+class Client(client.Client):
+ ''' derives basic CGI implementation from the standard module,
+ with any specific extensions
+ '''
+ pass
+
+class TemplatingUtils:
+ ''' Methods implemented on this class will be available to HTML templates
+ through the 'utils' variable.
+ '''
+ pass
+
+class MailGW(mailgw.MailGW):
+ ''' derives basic mail gateway implementation from the standard module,
+ with any specific extensions
+ '''
+ pass
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/minimal/.cvsignore b/templates/minimal/.cvsignore
--- /dev/null
@@ -0,0 +1,4 @@
+*.pyc
+*.pyo
+htmlbase.py
+*.cover
diff --git a/templates/minimal/TEMPLATE-INFO.txt b/templates/minimal/TEMPLATE-INFO.txt
--- /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/templates/minimal/__init__.py b/templates/minimal/__init__.py
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# 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: __init__.py,v 1.1 2003-04-17 03:27:27 richard Exp $
+
+import config
+from dbinit import open, init
+from interfaces import Client, MailGW
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/minimal/config.py b/templates/minimal/config.py
--- /dev/null
@@ -0,0 +1,99 @@
+#
+# 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: config.py,v 1.1 2003-04-17 03:27:27 richard Exp $
+
+import os
+
+# roundup home is this package's directory
+TRACKER_HOME=os.path.split(__file__)[0]
+
+# The SMTP mail host that roundup will use to send mail
+MAILHOST = 'localhost'
+
+# The domain name used for email addresses.
+MAIL_DOMAIN = 'your.tracker.email.domain.example'
+
+# This is the directory that the database is going to be stored in
+DATABASE = os.path.join(TRACKER_HOME, 'db')
+
+# This is the directory that the HTML templates reside in
+TEMPLATES = os.path.join(TRACKER_HOME, 'html')
+
+# A descriptive name for your roundup instance
+TRACKER_NAME = 'Roundup issue tracker'
+
+# The email address that mail to roundup should go to
+TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
+
+# The web address that the tracker is viewable at. This will be included in
+# information sent to users of the tracker. The URL MUST include the cgi-bin
+# part or anything else that is required to get to the home page of the
+# tracker. You MUST include a trailing '/' in the URL.
+TRACKER_WEB = 'http://tracker.example/cgi-bin/roundup.cgi/bugs/'
+
+# The email address that roundup will complain to if it runs into trouble
+ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
+
+# Additional text to include in the "name" part of the From: address used
+# in nosy messages. If the sending user is "Foo Bar", the From: line is
+# usually: "Foo Bar" <issue_tracker@tracker.example>
+# the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
+# "Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>
+EMAIL_FROM_TAG = ""
+
+#
+# SECURITY DEFINITIONS
+#
+# define the Roles that a user gets when they register with the tracker
+# these are a comma-separated string of role names (e.g. 'Admin,User')
+NEW_WEB_USER_ROLES = 'User'
+NEW_EMAIL_USER_ROLES = 'User'
+
+# Send nosy messages to the author of the message
+MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no'
+
+# Does the author of a message get placed on the nosy list automatically?
+# If 'new' is used, then the author will only be added when a message
+# creates a new issue. If 'yes', then the author will be added on followups
+# too. If 'no', they're never added to the nosy.
+ADD_AUTHOR_TO_NOSY = 'new' # one of 'yes', 'no', 'new'
+
+# Do the recipients (To:, Cc:) of a message get placed on the nosy list?
+# If 'new' is used, then the recipients will only be added when a message
+# creates a new issue. If 'yes', then the recipients will be added on followups
+# too. If 'no', they're never added to the nosy.
+ADD_RECIPIENTS_TO_NOSY = 'new' # either 'yes', 'no', 'new'
+
+# Where to place the email signature
+EMAIL_SIGNATURE_POSITION = 'bottom' # one of 'top', 'bottom', 'none'
+
+# Keep email citations when accepting messages. Setting this to "no" strips
+# out "quoted" text from the message. Signatures are also stripped.
+EMAIL_KEEP_QUOTED_TEXT = 'yes' # either 'yes' or 'no'
+
+# Preserve the email body as is - that is, keep the citations _and_
+# signatures.
+EMAIL_LEAVE_BODY_UNCHANGED = 'no' # either 'yes' or 'no'
+
+# Default class to use in the mailgw if one isn't supplied in email
+# subjects. To disable, comment out the variable below or leave it blank.
+# Examples:
+MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default
+#MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out)
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/minimal/dbinit.py b/templates/minimal/dbinit.py
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# 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: dbinit.py,v 1.1 2003-04-17 03:27:27 richard Exp $
+
+import os
+
+import config
+from select_db import Database, Class, FileClass, IssueClass
+
+def open(name=None):
+ ''' as from the roundupdb method openDB
+ '''
+ from roundup.hyperdb import String, Password, Date, Link, Multilink
+ from roundup.hyperdb import Interval, Boolean, Number
+
+ # open the database
+ db = Database(config, name)
+
+ #
+ # Now initialise the schema. Must do this each time the database is
+ # opened.
+ #
+
+ # 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")
+
+ # add any additional database schema configuration here
+
+ #
+ # SECURITY SETTINGS
+ #
+ # new permissions for this schema
+ for cl in ('user', ):
+ db.security.addPermission(name="Edit", klass=cl,
+ description="User is allowed to edit "+cl)
+ db.security.addPermission(name="View", klass=cl,
+ description="User is allowed to access "+cl)
+
+ # and give the regular users access to the web and email interface
+ p = db.security.getPermission('Web Access')
+ db.security.addPermissionToRole('User', p)
+ p = db.security.getPermission('Email Access')
+ db.security.addPermissionToRole('User', p)
+
+ # May users view other user information? Comment these lines out
+ # if you don't want them to
+ p = db.security.getPermission('View', 'user')
+ db.security.addPermissionToRole('User', p)
+
+ # Assign the appropriate permissions to the anonymous user's Anonymous
+ # Role. Choices here are:
+ # - Allow anonymous users to register through the web
+ p = db.security.getPermission('Web Registration')
+ db.security.addPermissionToRole('Anonymous', p)
+ # - Allow anonymous (new) users to register through the email gateway
+ p = db.security.getPermission('Email Registration')
+ db.security.addPermissionToRole('Anonymous', p)
+
+ import detectors
+ detectors.init(db)
+
+ # schema is set up - run any post-initialisation
+ db.post_init()
+ return db
+
+def init(adminpw):
+ ''' as from the roundupdb method initDB
+
+ Open the new database, and add new nodes - used for initialisation. You
+ can edit this before running the "roundup-admin initialise" command to
+ change the initial database entries.
+ '''
+ dbdir = os.path.join(config.DATABASE, 'files')
+ if not os.path.isdir(dbdir):
+ os.makedirs(dbdir)
+
+ db = open("admin")
+ db.clear()
+
+ # create the two default users
+ user = db.getclass('user')
+ user.create(username="admin", password=adminpw,
+ address=config.ADMIN_EMAIL, roles='Admin')
+ user.create(username="anonymous", roles='Anonymous')
+
+ # add any additional database create steps here - but only if you
+ # haven't initialised the database with the admin "initialise" command
+
+ db.commit()
+
+# vim: set filetype=python ts=4 sw=4 et si
+
diff --git a/templates/minimal/detectors/.cvsignore b/templates/minimal/detectors/.cvsignore
--- /dev/null
@@ -0,0 +1,3 @@
+*.pyc
+*.pyo
+*.cover
diff --git a/templates/minimal/detectors/__init__.py b/templates/minimal/detectors/__init__.py
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# 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: __init__.py,v 1.1 2003-04-17 03:27:56 richard Exp $
+
+import sys, os, imp
+
+def init(db):
+ ''' execute the init functions of all the modules in this directory
+ '''
+ this_dir = os.path.split(__file__)[0]
+ for file in os.listdir(this_dir):
+ path = os.path.join(this_dir, file)
+ name, ext = os.path.splitext(file)
+ if name == '__init__':
+ continue
+ if ext == '.py':
+ module = imp.load_module(name, open(path), file,
+ ('.py', 'r', imp.PY_SOURCE))
+ print (name, open(path), file, module)
+ module.init(db)
+
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/minimal/html/_generic.help.html b/templates/minimal/html/_generic.help.html
--- /dev/null
@@ -0,0 +1,16 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
+<link rel="stylesheet" type="text/css" href="_file/style.css">
+</head>
+<body class="body" marginwidth="0" marginheight="0">
+
+<table class="classhelp"
+ tal:define="props python:request.form['properties'].value.split(',')">
+<tr><th tal:repeat="prop props" tal:content="prop"></th></tr>
+<tr tal:repeat="item context/list">
+ <td tal:repeat="prop props" tal:content="python:item[prop]"></td>
+</tr>
+</table>
+
+</body>
diff --git a/templates/minimal/html/_generic.index.html b/templates/minimal/html/_generic.index.html
--- /dev/null
@@ -0,0 +1,48 @@
+<!-- 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"
+ tal:content="python:context._classname.capitalize()+' editing'"></title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<tal:block tal:condition="context/is_edit_ok">
+<p class="form-help">
+ You may edit the contents of the <span tal:replace="request/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>
+
+<form onSubmit="return submit_once()" method="POST">
+<textarea rows="15" cols="60" name="rows" tal:content="context/csv"></textarea>
+<br>
+<input type="hidden" name=":action" value="editCSV">
+<input type="submit" value="Edit Items">
+</form>
+</tal:block>
+
+<tal:block tal:condition="context/is_only_view_ok">
+view ok
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/templates/minimal/html/_generic.item.html b/templates/minimal/html/_generic.item.html
--- /dev/null
@@ -0,0 +1,56 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title"
+ tal:content="python:context._classname.capitalize()+' editing'"></title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2 tal:content="python:context._classname.capitalize()+' editing'"></h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<form method="POST" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<input type="hidden" name=":template" value="item">
+<input type="hidden" name=":required" value="title">
+
+<table class="form">
+
+<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>
+<tr>
+ <td> </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/home.classlist.html b/templates/minimal/html/home.classlist.html
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">List of classes</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>List of classes</h2>
+</td>
+<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
--- /dev/null
@@ -0,0 +1,25 @@
+<tal:block metal:use-macro="templates/page/macros/icing">
+<title metal:fill-slot="head_title">Tracker home</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>Tracker home</h2>
+</td>
+<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">
+Please select from one of the menu options on the right.
+</p>
+<p tal:condition="anon" class="help">
+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
--- /dev/null
@@ -0,0 +1,69 @@
+<html metal:define-macro="icing">
+<head>
+<title metal:define-slot="head_title">title goes here</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8;">
+
+<link rel="stylesheet" type="text/css" href="_file/style.css">
+
+<script tal:replace="structure request/base_javascript">
+</script>
+
+</head>
+<body class="body" marginwidth="0" marginheight="0">
+
+<table class="body">
+
+<tr>
+ <td class="page-header-left"> </td>
+ <td class="page-header-top" metal:define-slot="body_title"><h2>name</h2></td>
+</tr>
+
+<tr>
+ <td rowspan="2" valign="top" nowrap class="sidebar">
+ <p class="userblock" tal:condition="python:request.user.username=='anonymous'">
+ <form method="POST" action="">
+ <input size="10" name="__login_name"><br>
+ <input size="10" type="password" name="__login_password"><br>
+ <input type="submit" name=":action" value="login">
+ <span tal:replace="structure request/indexargs_form" />
+ </form>
+ <a href="user?:template=register">Register</a>
+ </p>
+
+ <p class="userblock" tal:condition="python:request.user.username != 'anonymous'">
+ <b>Hello,</b><br><b tal:content="request/user/username">username</b><br>
+ <a tal:attributes="href string:user${request/user/id}">My Details</a><br>
+ <a tal:attributes="href python:request.indexargs_href('',
+ {':action':'logout'})">Logout</a>
+ </p>
+
+ <p class="classblock"
+ tal:condition="python:request.user.username != 'anonymous'">
+ <b>Administration</b><br>
+ <a tal:condition="python:request.user.hasPermission('Edit', None)"
+ href="home?:template=classlist">Class List</a><br>
+ <a tal:condition="python:request.user.hasPermission('View', 'user')
+ or request.user.hasPermission('Edit', 'user')"
+ href="user" >User List</a><br>
+ <a tal:condition="python:request.user.hasPermission('Edit', 'user')"
+ href="user?:template=item">Add User</a>
+ </p>
+ </td>
+ <td>
+ <p tal:condition="options/error_message | nothing" class="error-message"
+ tal:repeat="m options/error_message" tal:content="structure m">error</p>
+ <p tal:condition="options/ok_message | nothing" class="ok-message"
+ tal:repeat="m options/ok_message" tal:content="structure m">error</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>
diff --git a/templates/minimal/html/style.css b/templates/minimal/html/style.css
--- /dev/null
@@ -0,0 +1,319 @@
+/* main page styles */
+body.body {
+ font-family: sans-serif, Arial, Helvetica;
+ color: #333333;
+}
+a[href]:hover { color:blue; text-decoration: underline; }
+a[href]:link { color:blue; text-decoration: none; }
+a[href] { color:blue; text-decoration: none; }
+
+table.body {
+ border: 0;
+ padding: 0;
+ border-spacing: 0px;
+ border-collapse: separate;
+}
+
+td.page-header-left {
+ padding: 5px;
+ border-bottom: 1px solid #444444;
+}
+
+td.page-header-top {
+ padding: 5px;
+ border-bottom: 1px solid #444444;
+}
+
+td.sidebar {
+ padding: 1 0 0 1;
+}
+
+td.sidebar p.classblock {
+ padding: 0 5 0 5;
+ margin: 1 1 1 1;
+ border: 1px solid #444444;
+ background-color: #eeeeee;
+}
+
+td.sidebar p.userblock {
+ padding: 0 5 0 5;
+ margin: 1 1 1 1;
+ border: 1px solid #444444;
+ background-color: #eeeeff;
+}
+
+td.content {
+ padding: 1 5 1 5;
+ vertical-align: top;
+ width: 100%;
+}
+
+p.ok-message {
+ background-color: #22bb22;
+ padding: 5 5 5 5;
+ color: white;
+ font-weight: bold;
+}
+p.error-message {
+ background-color: #bb2222;
+ padding: 5 5 5 5;
+ color: white;
+ font-weight: bold;
+}
+
+
+/* style for forms */
+table.form {
+ padding: 2;
+ border-spacing: 0px;
+ border-collapse: separate;
+}
+
+table.form th {
+ font-weight: bold;
+ color: #333388;
+ text-align: right;
+ vertical-align: top;
+}
+
+table.form th.header {
+ font-weight: bold;
+ color: #333388;
+ background-color: #eeeeff;
+ text-align: left;
+}
+
+table.form td {
+ color: #333333;
+ empty-cells: show;
+ vertical-align: top;
+}
+
+table.form td.optional {
+ font-weight: bold;
+ font-style: italic;
+}
+
+table.form td.html {
+ color: #777777;
+}
+
+/* style for lists */
+table.list {
+ border-spacing: 0px;
+ border-collapse: separate;
+ width: 100%;
+}
+
+table.list th {
+ padding: 0 4 0 4;
+ color: #404070;
+ background-color: #eeeeff;
+ border-right: 1px solid #404070;
+ border-top: 1px solid #404070;
+ border-bottom: 1px solid #404070;
+ 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 4 0 4;
+ border: 0 2 0 2;
+ border-right: 1px solid #404070;
+ color: #404070;
+ background-color: white;
+ vertical-align: top;
+ empty-cells: show;
+}
+
+table.list tr.normal td {
+ background-color: white;
+}
+
+table.list tr.alt td {
+ background-color: #efefef;
+}
+
+table.list td:first-child {
+ border-left: 1px solid #404070;
+ border-right: 1px solid #404070;
+}
+
+table.list th:first-child {
+ border-left: 1px solid #404070;
+ border-right: 1px solid #404070;
+}
+
+table.list tr.navigation th {
+ text-align: right;
+}
+table.list tr.navigation th:first-child {
+ border-right: none;
+ text-align: left;
+}
+
+
+/* style for message displays */
+table.messages {
+ border-spacing: 0px;
+ 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: 2 5 2 5;
+}
+
+table.messages td:first-child {
+ border-left: 1px solid #afafaf;
+ border-right: 1px solid #afafaf;
+}
+
+/* style for file displays */
+table.files {
+ border-spacing: 0px;
+ 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: 0px;
+ 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: 0px;
+ 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 {
+ border-spacing: 0px;
+ border-collapse: separate;
+ width: 100%;
+}
+
+table.classhelp th {
+ font-weight: bold;
+ text-align: left;
+ color: #707040;
+}
+
+table.classhelp td {
+ padding: 2 2 2 2;
+ border: 1px solid black;
+ text-align: left;
+ vertical-align: top;
+ empty-cells: show;
+}
+
+
+/* style for "other" displays */
+table.otherinfo {
+ border-spacing: 0px;
+ 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
--- /dev/null
@@ -0,0 +1,29 @@
+<!-- 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">User listing</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>User listing</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+
+<span tal:condition="not:context/is_view_ok">
+You are not allowed to view this page.
+</span>
+
+<table width="100%" tal:condition="context/is_view_ok" class="list">
+<tr>
+ <th>Username</th>
+ <th>Email address</th>
+</tr>
+<tr tal:repeat="user context/list"
+ 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>
+</table>
+</td>
+
+</tal:block>
diff --git a/templates/minimal/html/user.item.html b/templates/minimal/html/user.item.html
--- /dev/null
@@ -0,0 +1,70 @@
+<!-- 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">User editing</title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2>User editing</h2>
+</td>
+<td class="content" metal:fill-slot="content">
+<span tal:condition="python:not (context.is_view_ok() or context.is_edit_ok())">
+You are not allowed to view this page.
+</span>
+
+<form method="POST" onSubmit="return submit_once()"
+ enctype="multipart/form-data" tal:condition="context/is_edit_ok">
+
+<input type="hidden" name=":required" value="username,address">
+
+<table class="form">
+ <tr>
+ <th>Login Name</th>
+ <td tal:content="structure context/username/field">username</td>
+ </tr>
+ <tr>
+ <th>Login Password</th>
+ <td tal:content="structure context/password/field">password</td>
+ </tr>
+ <tr>
+ <th>Confirm Password</th>
+ <td tal:content="structure context/password/confirm">password</td>
+ </tr>
+ <tr tal:condition="python:request.user.hasPermission('Web Roles')">
+ <th>Roles</th>
+ <td tal:condition="context/id"
+ tal:content="structure context/roles/field">roles</td>
+ <td tal:condition="not:context/id">
+ <input name="roles" tal:attributes="value db/config/NEW_WEB_USER_ROLES">
+ </td>
+ </tr>
+ <tr>
+ <th>E-mail address</th>
+ <td tal:content="structure context/address/field">address</td>
+ </tr>
+ <tr>
+ <th>Alternate E-mail addresses<br>One address per line</th>
+ <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
+ </tr>
+
+ <tr>
+ <td> </td>
+ <td tal:content="structure context/submit">submit button here</td>
+ </tr>
+</table>
+</form>
+
+<table class="form" tal:condition="context/is_only_view_ok">
+ <tr>
+ <th>Login Name</th>
+ <td tal:content="context/username">username</td>
+ </tr>
+ <tr>
+ <th>E-mail address</th>
+ <td tal:content="context/address/email">address</td>
+ </tr>
+</table>
+
+<tal:block tal:condition="python:context.id and context.is_view_ok()"
+ tal:replace="structure context/history" />
+
+</td>
+
+</tal:block>
diff --git a/templates/minimal/html/user.register.html b/templates/minimal/html/user.register.html
--- /dev/null
@@ -0,0 +1,82 @@
+<!-- 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"
+ tal:content="string:Registering with ${db/config/TRACKER_NAME}"></title>
+<td class="page-header-top" metal:fill-slot="body_title">
+ <h2 tal:content="string:Registering with ${db/config/TRACKER_NAME}"></h2>
+</td>
+<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">
+You are not allowed to view this page.
+</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>Name</th>
+ <td tal:content="structure context/realname/field">realname</td>
+ </tr>
+ <tr>
+ <th>Login Name</th>
+ <td tal:content="structure context/username/field">username</td>
+ </tr>
+ <tr>
+ <th>Login Password</th>
+ <td tal:content="structure context/password/field">password</td>
+ </tr>
+ <tr>
+ <th>Confirm Password</th>
+ <td tal:content="structure context/password/confirm">password</td>
+ </tr>
+ <tr tal:condition="python:request.user.hasPermission('Web Roles')">
+ <th>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>Phone</th>
+ <td tal:content="structure context/phone/field">phone</td>
+ </tr>
+ <tr>
+ <th>Organisation</th>
+ <td tal:content="structure context/organisation/field">organisation</td>
+ </tr>
+ <tr>
+ <th>E-mail address</th>
+ <td tal:content="structure context/address/field">address</td>
+ </tr>
+ <tr>
+ <th>Alternate E-mail addresses<br>One address per line</th>
+ <td tal:content="structure context/alternate_addresses/multiline">alternate_addresses</td>
+ </tr>
+
+ <tr>
+ <td> </td>
+ <td>
+ <input type="hidden" name=":action" value="register">
+ <input type="submit" name="submit" value="Register">
+ </td>
+ </tr>
+</table>
+</form>
+
+</tal:block>
+
+</tal:block>
+
+</td>
+
+</tal:block>
diff --git a/templates/minimal/interfaces.py b/templates/minimal/interfaces.py
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# 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: interfaces.py,v 1.1 2003-04-17 03:27:27 richard Exp $
+
+from roundup import mailgw
+from roundup.cgi import client
+
+class Client(client.Client):
+ ''' derives basic CGI implementation from the standard module,
+ with any specific extensions
+ '''
+ pass
+
+class TemplatingUtils:
+ ''' Methods implemented on this class will be available to HTML templates
+ through the 'utils' variable.
+ '''
+ pass
+
+class MailGW(mailgw.MailGW):
+ ''' derives basic mail gateway implementation from the standard module,
+ with any specific extensions
+ '''
+ pass
+
+# vim: set filetype=python ts=4 sw=4 et si