# HG changeset patch # User Richard Jones # Date 1090889839 0 # Node ID a9e1fff1e79338e22ae70e19e3a4a867f4122c9f # Parent 9c55f2bc59617baaafaf025d040161c087bd2ef2 I thought I committed this last night. Ho hum. - This implements most of the rest of the new tracker config layout: - dbinit.py split between schema.py and initial_data.py - interfaces.py gone - tracker and detectors __init__.py gone - Added some missing functionality to backends: db_exists test and db_nuke. - Implemented configuration file options in postgresql backend. - Cleaned up tracker initialisation a lot. diff -r 9c55f2bc5961 -r a9e1fff1e793 cgi-bin/roundup.cgi --- a/cgi-bin/roundup.cgi Tue Jul 27 00:45:49 2004 +0000 +++ b/cgi-bin/roundup.cgi Tue Jul 27 00:57:19 2004 +0000 @@ -16,7 +16,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundup.cgi,v 1.39 2004-06-29 08:59:08 richard Exp $ +# $Id: roundup.cgi,v 1.40 2004-07-27 00:57:17 richard Exp $ # python version check from roundup import version_check @@ -158,16 +158,19 @@ else: tracker_home = TRACKER_HOMES[tracker] tracker = roundup.instance.open(tracker_home) - from roundup.cgi.client import Unauthorised, NotFound - client = tracker.Client(tracker, request, os.environ) + from roundup.cgi import client + if hasattr(tracker, 'Client'): + client = tracker.Client(tracker, request, os.environ) + else: + client = client.Client(tracker, request, os.environ) try: client.main() - except Unauthorised: + except client.Unauthorised: request.send_response(403) request.send_header('Content-Type', 'text/html') request.end_headers() out.write('Unauthorised') - except NotFound: + except client.NotFound: request.send_response(404) request.send_header('Content-Type', 'text/html') request.end_headers() diff -r 9c55f2bc5961 -r a9e1fff1e793 demo.py --- a/demo.py Tue Jul 27 00:45:49 2004 +0000 +++ b/demo.py Tue Jul 27 00:57:19 2004 +0000 @@ -2,7 +2,7 @@ # # Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net) # -# $Id: demo.py,v 1.11 2004-05-28 01:09:10 richard Exp $ +# $Id: demo.py,v 1.12 2004-07-27 00:57:17 richard Exp $ import sys, os, string, re, urlparse import shutil, socket, errno, BaseHTTPServer @@ -27,7 +27,7 @@ module.db_nuke(config) elif backend == 'postgresql': class config: - POSTGRESQL_DATABASE = {'database': 'rounduptest'} + POSTGRESQL_DATABASE = 'rounduptest' DATABASE = 'home' if module.db_exists(config): module.db_nuke(config) diff -r 9c55f2bc5961 -r a9e1fff1e793 frontends/ZRoundup/ZRoundup.py --- a/frontends/ZRoundup/ZRoundup.py Tue Jul 27 00:45:49 2004 +0000 +++ b/frontends/ZRoundup/ZRoundup.py Tue Jul 27 00:57:19 2004 +0000 @@ -14,7 +14,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: ZRoundup.py,v 1.18 2004-07-21 04:50:40 richard Exp $ +# $Id: ZRoundup.py,v 1.19 2004-07-27 00:57:17 richard Exp $ # ''' ZRoundup module - exposes the roundup web interface to Zope @@ -40,7 +40,7 @@ modulesecurity = ModuleSecurityInfo() import roundup.instance -from roundup.cgi.client import NotFound +from roundup.cgi import client modulesecurity.declareProtected('View management screens', 'manage_addZRoundupForm') @@ -139,7 +139,7 @@ def roundup_opendb(self): '''Open the roundup instance database for a transaction. ''' - instance = roundup.instance.open(self.instance_home) + tracker = roundup.instance.open(self.instance_home) request = RequestWrapper(self.REQUEST['RESPONSE']) env = self.REQUEST.environ @@ -159,7 +159,9 @@ env['TRACKER_NAME'] = path_components[-1] form = FormWrapper(self.REQUEST.form) - return instance.Client(instance, request, env, form) + if hasattr(tracker, 'Client'): + return tracker.Client(tracker, request, env, form) + return client.Client(tracker, request, env, form) security.declareProtected('View', 'index_html') def index_html(self): @@ -208,7 +210,7 @@ # and call roundup to do something client.main() return '' - except NotFound: + except client.NotFound: raise 'NotFound', REQUEST.URL pass except: diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/admin.py --- a/roundup/admin.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/admin.py Tue Jul 27 00:57:19 2004 +0000 @@ -16,7 +16,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: admin.py,v 1.76 2004-07-13 10:21:32 a1s Exp $ +# $Id: admin.py,v 1.77 2004-07-27 00:57:17 richard Exp $ '''Administration commands for maintaining Roundup trackers. ''' @@ -445,12 +445,7 @@ raise UsageError, _('Instance has not been installed')%locals() # is there already a database? - try: - db_exists = tracker.select_db.Database.exists(tracker.config) - except AttributeError: - # TODO: move this code to exists() static method in every backend - db_exists = os.path.exists(os.path.join(tracker_home, 'db')) - if db_exists: + if tracker.exists(): ok = raw_input(_( """WARNING: The database is already initialised! If you re-initialise it, you will lose all the data! @@ -458,16 +453,11 @@ if ok.strip().lower() != 'y': return 0 - # Get a database backend in use by tracker - try: - # nuke it - tracker.select_db.Database.nuke(tracker.config) - except AttributeError: - # TODO: move this code to nuke() static method in every backend - shutil.rmtree(os.path.join(tracker_home, 'db')) + # nuke it + tracker.nuke() # GO - init.initialise(tracker_home, adminpw) + tracker.init(password.Password(adminpw)) return 0 diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/backends/back_anydbm.py --- a/roundup/backends/back_anydbm.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/backends/back_anydbm.py Tue Jul 27 00:57:19 2004 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_anydbm.py,v 1.166 2004-07-22 04:47:35 richard Exp $ +#$Id: back_anydbm.py,v 1.167 2004-07-27 00:57:18 richard Exp $ '''This module defines a backend that saves the hyperdatabase in a database chosen by anydbm. It is guaranteed to always be available in python versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several @@ -43,6 +43,16 @@ Multilink, DatabaseError, Boolean, Number, Node from roundup.date import Range +def db_exists(config): + # check for the user db + for db in 'user user.db'.split(): + if os.path.exists(os.path.join(config.TRACKER_HOME, 'db', db)): + return 1 + return 0 + +def db_nuke(config): + shutil.rmtree(os.path.join(config.TRACKER_HOME, 'db')) + # # Now the database # diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/backends/back_bsddb.py --- a/roundup/backends/back_bsddb.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/backends/back_bsddb.py Tue Jul 27 00:57:19 2004 +0000 @@ -15,17 +15,23 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb.py,v 1.30 2004-07-02 05:22:09 richard Exp $ +#$Id: back_bsddb.py,v 1.31 2004-07-27 00:57:18 richard Exp $ '''This module defines a backend that saves the hyperdatabase in BSDDB. ''' __docformat__ = 'restructuredtext' -import bsddb, os, marshal +import bsddb, os, marshal, shutil from roundup import hyperdb, date # these classes are so similar, we just use the anydbm methods from back_anydbm import Database, Class, FileClass, IssueClass +def db_exists(config): + return os.path.exists(os.path.join(config.TRACKER_HOME, 'db', 'user')) + +def db_nuke(config): + shutil.rmtree(os.path.join(config.TRACKER_HOME, 'db')) + # # Now the database # diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/backends/back_bsddb3.py --- a/roundup/backends/back_bsddb3.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/backends/back_bsddb3.py Tue Jul 27 00:57:19 2004 +0000 @@ -15,17 +15,23 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb3.py,v 1.24 2004-07-02 05:22:09 richard Exp $ +#$Id: back_bsddb3.py,v 1.25 2004-07-27 00:57:18 richard Exp $ '''This module defines a backend that saves the hyperdatabase in BSDDB3. ''' __docformat__ = 'restructuredtext' -import bsddb3, os, marshal, errno +import bsddb3, os, marshal, errno, shutil from roundup import hyperdb, date # these classes are so similar, we just use the anydbm methods from back_anydbm import Database, Class, FileClass, IssueClass +def db_exists(config): + return os.path.exists(os.path.join(config.TRACKER_HOME, 'db', 'user')) + +def db_nuke(config): + shutil.rmtree(os.path.join(config.TRACKER_HOME, 'db')) + # # Now the database # diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/backends/back_metakit.py --- a/roundup/backends/back_metakit.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/backends/back_metakit.py Tue Jul 27 00:57:19 2004 +0000 @@ -1,4 +1,4 @@ -# $Id: back_metakit.py,v 1.81 2004-07-20 23:24:26 richard Exp $ +# $Id: back_metakit.py,v 1.82 2004-07-27 00:57:18 richard Exp $ '''Metakit backend for Roundup, originally by Gordon McMillan. Known Current Bugs: @@ -56,6 +56,13 @@ READ = 0 READWRITE = 1 +def db_exists(config): + return os.path.exists(os.path.join(config.TRACKER_HOME, 'db', + 'tracker.mk4')) + +def db_nuke(config): + shutil.rmtree(os.path.join(config.TRACKER_HOME, 'db')) + # general metakit error class MKBackendError(Exception): pass diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/backends/back_postgresql.py --- a/roundup/backends/back_postgresql.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/backends/back_postgresql.py Tue Jul 27 00:57:19 2004 +0000 @@ -14,15 +14,37 @@ from roundup import hyperdb, date from roundup.backends import rdbms_common +from roundup import configuration + +configuration.SETTINGS += ( + ("postgresql", ( + (configuration.Option, 'database', 'roundup'), + (configuration.NullableOption, 'host', 'localhost'), + (configuration.NullableOption, 'port', '5432'), + (configuration.NullableOption, 'user', 'roundup'), + (configuration.NullableOption, 'password', 'roundup'), + )), +) + +def connection_dict(config): + d = { + 'database': config.POSTGRESQL_DATABASE, + } + for name in 'host', 'port', 'password', 'user': + cvar = 'POSTGRESQL_'+name.upper() + if config[cvar] is not None: + d[name] = config[cvar] + return d + def db_create(config): """Clear all database contents and drop database itself""" - command = 'CREATE DATABASE %s'%config.POSTGRESQL_DATABASE['database'] + command = 'CREATE DATABASE %s'%config.POSTGRESQL_DATABASE config.logging.getLogger('hyperdb').info(command) db_command(config, command) def db_nuke(config, fail_ok=0): """Clear all database contents and drop database itself""" - command = 'DROP DATABASE %s'% config.POSTGRESQL_DATABASE['database'] + command = 'DROP DATABASE %s'% config.POSTGRESQL_DATABASE config.logging.getLogger('hyperdb').info(command) db_command(config, command) @@ -33,7 +55,7 @@ '''Perform some sort of database-level command. Retry 10 times if we fail by conflicting with another user. ''' - template1 = config.POSTGRESQL_DATABASE.copy() + template1 = connection_dict(config) template1['database'] = 'template1' try: @@ -70,7 +92,7 @@ def db_exists(config): """Check if database already exists""" - db = getattr(config, 'POSTGRESQL_DATABASE') + db = connection_dict(config) try: conn = psycopg.connect(**db) conn.close() @@ -82,7 +104,7 @@ arg = '%s' def sql_open_connection(self): - db = getattr(self.config, 'POSTGRESQL_DATABASE') + db = connection_dict(config) self.config.logging.getLogger('hyperdb').info('open database %r'%db) try: conn = psycopg.connect(**db) diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/backends/back_sqlite.py --- a/roundup/backends/back_sqlite.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/backends/back_sqlite.py Tue Jul 27 00:57:19 2004 +0000 @@ -1,4 +1,4 @@ -# $Id: back_sqlite.py,v 1.30 2004-07-02 05:22:09 richard Exp $ +# $Id: back_sqlite.py,v 1.31 2004-07-27 00:57:18 richard Exp $ '''Implements a backend for SQLite. See https://pysqlite.sourceforge.net/ for pysqlite info @@ -9,13 +9,19 @@ ''' __docformat__ = 'restructuredtext' -import os, base64, marshal +import os, base64, marshal, shutil from roundup import hyperdb, date, password from roundup.backends import locking from roundup.backends import rdbms_common import sqlite +def db_exists(config): + return os.path.exists(os.path.join(config.TRACKER_HOME, 'db', 'db')) + +def db_nuke(config): + shutil.rmtree(os.path.join(config.TRACKER_HOME, 'db')) + class Database(rdbms_common.Database): # char to use for positional arguments arg = '%s' diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/init.py --- a/roundup/init.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/init.py Tue Jul 27 00:57:19 2004 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: init.py,v 1.29 2004-02-11 23:55:08 richard Exp $ +# $Id: init.py,v 1.30 2004-07-27 00:57:18 richard Exp $ """Init (create) a roundup instance. """ @@ -159,20 +159,13 @@ def write_select_db(instance_home, backend): ''' Write the file that selects the backend for the tracker ''' - # now select database - db = '''# WARNING: DO NOT EDIT THIS FILE!!! -from roundup.backends.back_%s import Database, Class, FileClass, IssueClass -'''%backend - open(os.path.join(instance_home, 'select_db.py'), 'w').write(db) + dbdir = os.path.join(instance_home, 'db') + if not os.path.exists(dbdir): + os.makedirs(dbdir) + f = open(os.path.join(dbdir, 'backend_name'), 'w') + f.write(backend+'\n') + f.close() -def initialise(instance_home, adminpw): - '''Initialise an instance's database - - adminpw - the password for the "admin" user - ''' - # now import the instance and call its init - instance = roundup.instance.open(instance_home) - instance.init(password.Password(adminpw)) # vim: set filetype=python ts=4 sw=4 et si diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/instance.py --- a/roundup/instance.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/instance.py Tue Jul 27 00:57:19 2004 +0000 @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: instance.py,v 1.16 2004-07-25 13:14:57 a1s Exp $ +# $Id: instance.py,v 1.17 2004-07-27 00:57:18 richard Exp $ '''Tracker handling (open tracker). @@ -25,31 +25,80 @@ import os from roundup import configuration, rlog +from roundup import hyperdb, backends class Vars: - ''' I'm just a container ''' + def __init__(self, vars): + self.__dict__.update(vars) class Tracker: def __init__(self, tracker_home): self.tracker_home = tracker_home - self.select_db = self._load_python('select_db.py') - self.config = self._load_config('config.py') - raise NotImplemented, 'this is *so* not finished' - self.init = XXX - self.Client = XXX - self.MailGW = XXX + self.config = configuration.Config(tracker_home) + self.cgi_actions = {} + self.templating_utils = {} + + def get_backend(self): + o = __builtins__['open'] + f = o(os.path.join(self.tracker_home, 'db', 'backend_name')) + name = f.readline().strip() + f.close() + return getattr(backends, name) - def open(self): - return self._load_config('schema.py').db - self._load_config('security.py', db=db) - + def open(self, name): + backend = self.get_backend() + vars = { + 'Class': backend.Class, + 'FileClass': backend.FileClass, + 'IssueClass': backend.IssueClass, + 'String': hyperdb.String, + 'Password': hyperdb.Password, + 'Date': hyperdb.Date, + 'Link': hyperdb.Link, + 'Multilink': hyperdb.Multilink, + 'Interval': hyperdb.Interval, + 'Boolean': hyperdb.Boolean, + 'Number': hyperdb.Number, + 'db': backend.Database(self.config, name) + } + self._load_python('schema.py', vars) + db = vars['db'] - def _load_python(self, file): + detectors_dir = os.path.join(self.tracker_home, 'detectors') + for name in os.listdir(detectors_dir): + if not name.endswith('.py'): + continue + self._load_python(os.path.join('detectors', name), vars) + vars['init'](db) + + db.post_init() + return db + + def init(self, adminpw): + db = self.open('admin') + self._load_python('initial_data.py', {'db': db, 'adminpw': adminpw, + 'admin_email': self.config['ADMIN_EMAIL']}) + db.commit() + db.close() + + def exists(self): + backend = self.get_backend() + return backend.db_exists(self.config) + + def nuke(self): + backend = self.get_backend() + backend.db_nuke(self.config) + + def _load_python(self, file, vars): file = os.path.join(self.tracker_home, file) - vars = Vars() - execfile(file, vars.__dict__) + execfile(file, vars) return vars + def registerAction(self, name, action): + self.cgi_actions[name] = action + + def registerUtil(self, name, function): + self.templating_utils[name] = function class TrackerError(Exception): pass diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/scripts/roundup_mailgw.py --- a/roundup/scripts/roundup_mailgw.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/scripts/roundup_mailgw.py Tue Jul 27 00:57:19 2004 +0000 @@ -14,7 +14,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundup_mailgw.py,v 1.18 2004-05-28 00:56:50 richard Exp $ +# $Id: roundup_mailgw.py,v 1.19 2004-07-27 00:57:18 richard Exp $ """Command-line script stub that calls the roundup.mailgw. """ @@ -26,7 +26,7 @@ import sys, os, re, cStringIO, getopt -from roundup.mailgw import Message +from roundup import mailgw from roundup.i18n import _ def usage(args, message=None): @@ -132,7 +132,10 @@ # now wrap in try/finally so we always close the database try: - handler = instance.MailGW(instance, db, optionsList) + if hasattr(instance, 'MailGW'): + handler = instance.MailGW(instance, db, optionsList) + else: + handler = mailgw.MailGW(instance, db, optionsList) # if there's no more arguments, read a single message from stdin if len(args) == 1: diff -r 9c55f2bc5961 -r a9e1fff1e793 roundup/scripts/roundup_server.py --- a/roundup/scripts/roundup_server.py Tue Jul 27 00:45:49 2004 +0000 +++ b/roundup/scripts/roundup_server.py Tue Jul 27 00:57:19 2004 +0000 @@ -17,7 +17,7 @@ """Command-line script that runs a server over roundup.cgi.client. -$Id: roundup_server.py,v 1.57 2004-07-27 00:45:49 richard Exp $ +$Id: roundup_server.py,v 1.58 2004-07-27 00:57:18 richard Exp $ """ __docformat__ = 'restructuredtext' @@ -187,7 +187,10 @@ decoded_query = query.replace('+', ' ') # do the roundup thang - c = tracker.Client(tracker, self, env) + if hasattr(tracker, 'Client'): + c = tracker.Client(tracker, self, env) + else: + c = client.Client(tracker, self, env) c.main() def address_string(self): diff -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/__init__.py --- a/templates/classic/__init__.py Tue Jul 27 00:45:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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 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 -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/config.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/classic/config.ini Tue Jul 27 00:57:19 2004 +0000 @@ -0,0 +1,34 @@ + +[main] +database = %(TRACKER_HOME)s/db +templates = %(TRACKER_HOME)s/html +admin_email = roundup-admin +new_web_user_roles = User +new_email_user_roles = User +error_messages_to = user +html_version = html4 +default_timezone = 0 + +[tracker] +name = Roundup issue tracker +web = http://tracker.example/cgi-bin/roundup.cgi/bugs/ +emaiL = issue_tracker + +[logging] +level = ERROR + +[mail] +domain = your.tracker.email.domain.example +host = localhost +charset = utf-8 + +[mailgw] +email_keep_quoted_text = yes +email_leave_body_unchanged = no +mail_default_class = issue + +[nosy] +messages_to_author = no +add_author_to_nosy = new +add_recipients_to_nosy = new +email_signature_position = bottom diff -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/config.py --- a/templates/classic/config.py Tue Jul 27 00:45:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +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.10 2004-07-20 00:15:23 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' - -# If your SMTP mail host requires a username and password for access, then -# specify them here. -# eg. MAILUSER = ('username', 'password') -MAILUSER = () - -# If your SMTP mail host provides or requires TLS (Transport Layer -# Security) then set MAILHOST_TLS = 'yes' -# Optionallly, you may also set MAILHOST_TLS_KEYFILE to the name of a PEM -# formatted file that contains your private key, and MAILHOST_TLS_CERTFILE -# to the name of a PEM formatted certificate chain file. -MAILHOST_TLS = 'no' -MAILHOST_TLS_KEYFILE = '' -MAILHOST_TLS_CERTFILE = '' - -# 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') - -# Optional: the directory that static files are served from (files with the -# URL /@@file/). If this is not defined, then static files are -# served from the TEMPLATES directory. -# STATIC_FILES = os.path.join(TRACKER_HOME, 'files') - -# 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 - -# These variables define where to log Roundup's internal messages to. -# You have two choices - either using the standard Python logging module -# or a minimal logging facility built into Roundup. The former is activated -# when you provide a LOGGING_CONFIG variable below which contains the -# configuration of the logging module. The latter is activated when you -# provide the LOGGING_FILENAME and optionally LOGGING_LEVEL variables. If -# none of these variables are defined then only errors will be logged, and -# they will go to stderr. -# LOGGGING_CONFIG = os.path.join(TRACKER_HOME, 'logging.ini') -# or, -# LOGGING_FILENAME = '/path/to/log file' -# LOGGING_LEVEL = 'INFO' # one of 'DEBUG', 'INFO', 'WARNING', 'ERROR' - -# The 'dispatcher' is a role that can get notified of new items to the -# database. It is used by the ERROR_MESSAGES_TO config setting. -DISPATCHER_EMAIL = ADMIN_EMAIL - -# 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" -# the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so: -# "Foo Bar EMAIL_FROM_TAG" -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 error message emails to the dispatcher, user, or both? -# If 'dispatcher', error messages will only be sent to the dispatcher. -# If 'user', error messages will only be sent to the user. -# If 'both', error messages will be sent to both individuals. -# The dispatcher is configured using the DISPATCHER_EMAIL setting, which -# defaults to ADMIN_EMAIL. -ERROR_MESSAGES_TO = '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) - -# HTML version to generate. The templates are html4 by default. If you -# wish to make them xhtml, then you'll need to change this var to 'xhtml' -# too so all auto-generated HTML is compliant. -HTML_VERSION = 'html4' # either 'html4' or 'xhtml' - -# Character set to encode email headers with. We use utf-8 by default, as -# it's the most flexible. Some mail readers (eg. Eudora) can't cope with -# that, so you might need to specify a more limited character set (eg. -# 'iso-8859-1'. -EMAIL_CHARSET = 'utf-8' -#EMAIL_CHARSET = 'iso-8859-1' # use this instead for Eudora users - -# You may specify a different default timezone, for use when users do not -# choose their own in their settings. -DEFAULT_TIMEZONE = 0 # specify as numeric hour offest - -# vim: set filetype=python ts=4 sw=4 et si diff -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/dbinit.py --- a/templates/classic/dbinit.py Tue Jul 27 00:45:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +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.8 2004-05-02 23:16:05 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(), private_for=Link('user')) - - # 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 /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. - # 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) - for cl in 'priority', 'status': - p = db.security.getPermission('View', 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 view issues (which implies being - # able to view all linked information too - for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status': - p = db.security.getPermission('View', cl) - 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): - '''Invoked by the "roundup-admin initialise" command to set up the - initial state of the hyperdb. - - If you wish to change the hyperdb *after* running that command, see - the customisation doc "Database Content" section. - ''' - 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() - db.close() - -# vim: set filetype=python ts=4 sw=4 et si - -#SHA: 92c54c05ba9f59453dc74fa9fdbbae34f7a9c077 diff -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/detectors/__init__.py --- a/templates/classic/detectors/__init__.py Tue Jul 27 00:45:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +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.4 2003-10-07 06:18:45 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 filename in os.listdir(this_dir): - name, ext = os.path.splitext(filename) - if name == '__init__': - continue - if ext == '.py': - path = os.path.abspath(os.path.join(this_dir, filename)) - fp = open(path) - try: - module = imp.load_module(name, fp, path, - ('.py', 'r', imp.PY_SOURCE)) - finally: - fp.close() - module.init(db) - -# vim: set filetype=python ts=4 sw=4 et si diff -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/initial_data.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/classic/initial_data.py Tue Jul 27 00:57:19 2004 +0000 @@ -0,0 +1,32 @@ +# +# TRACKER INITIAL PRIORITY AND STATUS VALUES +# +pri = db.getclass('priority') +pri.create(name="critical", order="1") +pri.create(name="urgent", order="2") +pri.create(name="bug", order="3") +pri.create(name="feature", order="4") +pri.create(name="wish", order="5") + +stat = db.getclass('status') +stat.create(name="unread", order="1") +stat.create(name="deferred", order="2") +stat.create(name="chatting", order="3") +stat.create(name="need-eg", order="4") +stat.create(name="in-progress", order="5") +stat.create(name="testing", order="6") +stat.create(name="done-cbb", order="7") +stat.create(name="resolved", order="8") + +# create the two default users +user = db.getclass('user') +user.create(username="admin", password=adminpw, + address=admin_email, roles='Admin') +user.create(username="anonymous", roles='Anonymous') + +# add any additional database create steps here - but only if you +# haven't initialised the database with the admin "initialise" command + + +# vim: set filetype=python sts=4 sw=4 et si +#SHA: b1da2e72a7fe9f26086f243eb744135b085101d9 diff -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/interfaces.py --- a/templates/classic/interfaces.py Tue Jul 27 00:45:49 2004 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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.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 -r 9c55f2bc5961 -r a9e1fff1e793 templates/classic/schema.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/classic/schema.py Tue Jul 27 00:57:19 2004 +0000 @@ -0,0 +1,129 @@ + +# +# TRACKER SCHEMA +# + +# Class automatically gets these properties: +# creation = Date() +# activity = Date() +# creator = Link('user') +# actor = Link('user') + +# Priorities +pri = Class(db, "priority", + name=String(), + order=Number()) +pri.setkey("name") + +# Statuses +stat = Class(db, "status", + name=String(), + order=Number()) +stat.setkey("name") + +# Keywords +keyword = Class(db, "keyword", + name=String()) +keyword.setkey("name") + +# User-defined saved searches +query = Class(db, "query", + klass=String(), + name=String(), + url=String(), + private_for=Link('user')) + +# add any additional database schema configuration here + +user = Class(db, "user", + username=String(), + password=Password(), + address=String(), + realname=String(), + phone=String(), + organisation=String(), + alternate_addresses=String(), + queries=Multilink('query'), + roles=String(), # comma-separated string of Role names + timezone=String()) +user.setkey("username") + +# FileClass automatically gets this property in addition to the Class ones: +# content = String() [saved to disk in /db/files/] +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 in addition to the Class ones: +# title = String() +# messages = Multilink("msg") +# files = Multilink("file") +# nosy = Multilink("user") +# superseder = Multilink("issue") +issue = IssueClass(db, "issue", + assignedto=Link("user"), + topic=Multilink("keyword"), + priority=Link("priority"), + status=Link("status")) + +# +# TRACKER SECURITY SETTINGS +# +# See the configuration and customisation document for information +# about security setup. +# 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) +for cl in 'priority', 'status': + p = db.security.getPermission('View', 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 view issues (which implies being +# able to view all linked information too +for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status': + p = db.security.getPermission('View', cl) + 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) + + +# vim: set filetype=python sts=4 sw=4 et si