Commits

Ezio Melotti committed 155d752 Draft Merge

Merge with default.

Comments (0)

Files changed (112)

 locale/*.bak
 locale/*.poedit
 website/www/_tmp/
+website/www/COPYING.txt
 website/www/docs
 website/www/html/
 ffc6fa77e551fb74ae3ff6c71cc46ccfa58c5c1c 1.4.10
 ffd14fa75beceaeae8f6c64bafae0abbb95a3529 0.6.10
 59de7ad827e2f0070bd5ba49d4b27a00c69abd85 1.4.20
+d6e9f95cc30e1e5e965f1b6cfede55afb6db57f3 1.4.21
 Each entry has the developer who committed the change in brackets.
 Entries without name were done by Richard Jones.
 
-2012-??-??: 1.4.21
+2013-??-??: 1.4.22
 
 Features:
 
+- ...
+
+Fixed:
+
+- Make roundup play nice with setup tools (for using with virtualenv)
+  (Pradip Caulagi)
+- [minor] Template responsive: make demo.py work out of the box with it,
+  by setting the static_files config.ini setting to "static". 
+  Footer: link fixed and hardcoded last modfied date removed. (Bernhard Reiter)
+
+
+2012-12-21: 1.4.21
+
+Features:
+
+- issue2550782: Added a new irker detector to send notifications on IRC
+  when an issue is created or messages are added. (Ezio Melotti)
+- Beta version of responsive templates using devel schema
+  and Twitter Bootstrap for styling (Pradip Caulagi)
+- pywin32 is no longer required to run on Windows (anatoly techtonik)
+- Rewritten portalocker.py logic in ctypes for Windows (anatoly techtonik)
 - Add an interface to register clearCache callbacks in roundupdb.
   Sometimes complicated computations may require an application cache.
   This application can now register a callback to clear the application
   thanks Nathan Russell. (John Kristensen)
 - issue2550756: Fix `oder' typo in mailer.Mailer.bounce_message docstring,
   thanks W. Trevor King (John Kristensen)
+- Fix basic authentication: instatiating the login action would fail if
+  the user is not set. We now first set the user to anonymous and then
+  try basic authentication if enabled. (Ralf Schlatterbeck)
+- Fix xmlrpc permissions for lookup method: Allow if the key attribute
+  is either searchable or viewable, don't check id attribute (Ralf
+  Schlatterbeck)
+- Fix installation documentation (section Prerequisites) to require at
+  least python 2.5, thanks to John P. Rouillard for discovering this.
+  (committed by Ralf Schlatterbeck)
+- Fix version_check.py to require at least python 2.5 (anatoly techtonik)
+- Fixing the download button re-activating the cheeseshop plugin in the 
+  sphinx config. Thanks to Richard for the hint. (Bernhard Reiter)
+- issue2550783 devel template's schema.py permissions referenced the
+  organization property for the user, but the property is called
+  organisation. Thanks to Pradip Caulagi. (committed by John Rouillard)
+- issue2550749 - the xmlrpc interface is invoked on content type
+  and not url path. Sending any text/xml data to roundup results in
+  invoking the xml-rpc interface, but a REST or other interface could
+  also consume xml data and do something different. So require the use
+  of 'http(s)://.../xmlrpc' uri to trigger the xmlrpc interface.
+  (John Rouillard)
+- issue2550774: Remove generating documentation with rst2html, and update the
+  README.txt with how to create the html docs using sphinx, thanks Kai Storbeck
+  (John Kristensen)
+- issue2550774: Include doc/conf.py in the release tarball, so people can build
+  their own documentation in html, thanks Kai Storbeck (John Kristensen)
+- issue2550774: Update website/www/Makefile to symlink COPYING.txt so "make"
+  works again, thanks Kai Storbeck (John Kristensen)
+- issue2550760: Several improvements to the manpages
+  thanks Kai Storbeck & Bastian Kleineidam (John Kristensen)
 
 
 2012-05-15: 1.4.20
 recursive-include detectors *.py
 recursive-include templates *.* home* page*
 global-exclude .svn .cvsignore *.pyc *.pyo .DS_Store
-include run_tests.py *.txt demo.py MANIFEST.in MANIFEST
+include run_tests.py *.txt demo.py MANIFEST.in MANIFEST doc/conf.py
 exclude BUILD.txt I18N_PROGRESS.txt TODO.txt
 exclude doc/security.txt doc/templating.txt
 include locale/*.po locale/*.mo locale/roundup.pot
 ===========================
 See the index.txt file in the "doc" directory.
 The *.txt files in the "doc" directory are written in reStructedText. If
-you have rst2html installed (part of the docutils suite) you can convert
-these to HTML by running "make html" in the "doc" directory.
+you have Sphinx installed, you can convert these to HTML by running
+  $ python setup.py build_doc
+from the top of the release directory.
 
 
 For Developers
-#! /usr/bin/env python
+#!/usr/bin/env python
 #
 # Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net)
 #
 import socket
 import sys
 import urlparse
-from glob import glob
 import getopt
 
 from roundup import configuration
 
     # write the config
     config['INSTANT_REGISTRATION'] = 1
+    # FIXME: Move template-specific demo initialization into the templates.
+    if template == 'responsive':
+        config['STATIC_FILES'] = "static"
     config.save(os.path.join(home, config.INI_FILE))
 
     # open the tracker and initialise
     # add the "demo" user
     db = tracker.open('admin')
     # FIXME: Move tracker-specific demo initialization into the tracker templates.
-    if (template == 'minimal'):
+    if template == 'minimal':
         db.user.create(username='demo', password=password.Password('demo'),
                        roles='User')
     else:

detectors/irker.py

+# This detector sends notification on IRC through an irker daemon
+# (http://www.catb.org/esr/irker/) when issues are created or messages
+#  are added.
+#
+# Written by Ezio Melotti
+#
+# Requires a running irkerd daemon to work.  See the irker documentation
+# for more information about installing, configuring, and running irker.
+#
+# Add the IRC channel(s) that should receive notifications in
+# detectors/config.ini as a comma-separated list, using this format:
+#
+#   [irker]
+#   channels = irc://chat.freenode.net/channelname
+#
+
+import re
+import json
+import socket
+
+IRKER_HOST = 'localhost'
+IRKER_PORT = 6659
+
+max_content = 120
+
+TEMPLATE = ('%(green)s%(author)s%(reset)s '
+            '%(bluish)s#%(nodeid)s%(reset)s/%(title)s%(bold)s:%(bold)s '
+            '%(log)s %(url)s')
+
+
+def sendmsg(msg):
+    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    try:
+        sock.connect((IRKER_HOST, IRKER_PORT))
+        sock.sendall(msg + "\n")
+    finally:
+        sock.close()
+
+
+def notify_irker(db, cl, nodeid, oldvalues):
+    messages = set(cl.get(nodeid, 'messages'))
+    if oldvalues:
+        messages -= set(oldvalues.get('messages', ()))
+    if not messages:
+        return
+    messages = list(messages)
+
+    if oldvalues:
+        oldstatus = oldvalues['status']
+    else:
+        oldstatus = None
+    newstatus = db.issue.get(nodeid, 'status')
+    if oldstatus != newstatus:
+        if oldvalues:
+            status = db.status.get(newstatus, 'name')
+        else:
+            status = 'new'
+        log = '[' + status + '] '
+    else:
+        log = ''
+    for msg in messages:
+        log += db.msg.get(msg, 'content')
+    if len(log) > max_content:
+        log = log[:max_content-3] + '...'
+    log = re.sub('\s+', ' ', log)
+
+    # include irc colors
+    params = {
+        'bold': '\x02',
+        'green': '\x0303',
+        'blue': '\x0302',
+        'bluish': '\x0310',
+        'yellow': '\x0307',
+        'brown': '\x0305',
+        'reset': '\x0F'
+    }
+    # extend with values used in the template
+    params['author'] = db.user.get(db.getuid(), 'username')
+    params['nodeid'] = nodeid
+    params['title'] = db.issue.get(nodeid, 'title')
+    params['log'] = log
+    params['url'] = '%sissue%s' % (db.config.TRACKER_WEB, nodeid)
+
+    # create the message and use the list of channels defined in
+    # detectors/config.ini
+    msg = json.dumps({
+        'to': db.config.detectors.IRKER_CHANNELS.split(','),
+        'privmsg': TEMPLATE % params,
+    })
+
+    try:
+        sendmsg(msg)
+    except Exception as e:
+        # Ignore any errors in sending the irker;
+        # if the server is down, that's just bad luck
+        # XXX might want to do some logging here
+        print '* Sending message to irker failed', str(e)
+
+def init(db):
+    db.issue.react('create', notify_irker)
+    db.issue.react('set', notify_irker)

doc/Makefile

-STXTOHTML = rst2html.py
-WEBDIR = ../../htdocs/htdocs/doc-1.0
-
-SOURCE = announcement.txt customizing.txt developers.txt FAQ.txt features.txt \
-    glossary.txt implementation.txt index.txt design.txt mysql.txt \
-    installation.txt upgrading.txt user_guide.txt admin_guide.txt \
-	postgresql.txt tracker_templates.txt xmlrpc.txt
-
-COMPILED := $(SOURCE:.txt=.html)
-WEBHT := $(SOURCE:.txt=.ht)
-
-all: html
-html: ${COMPILED}
-
-website: ${WEBHT}
-	cp *.ht ${WEBDIR}
-	cp -r images ${WEBDIR}
-
-%.html: %.txt
-	${STXTOHTML} --report=warning -d $< $@
-
-clean:
-	rm -f ${COMPILED}

doc/acknowledgements.txt

 Steve Byan,
 Brett Cannon,
 Godefroid Chapelle,
+Pradip Caulagi,
 Eli Collins,
 Roch'e Compaan,
 Wil Cooley,

doc/announcement.txt

-I'm proud to release version 1.4.20 of Roundup which can be seen as a
-security release. We've fixed several security issues, in particular
-some XSS issues. We've also dropped support for python 2.4 with this
-release. This release also introduces some minor features and, as usual,
-fixes some bugs:
+I'm proud to release version 1.4.21 of Roundup which has been possible
+due to the help of several contributors.  This release introduces some
+minor features and, as usual, fixes some bugs:
 
 Features:
 
-- Experimental support for the new Chameleon templating engine.
-  We now have two configurable templating engines, the old Zope TAL
-  templates (called zopetal in the config) and the new Chameleon (called
-  chameleon in the config). A new config-option "template_engine" under
-  [main] can take these config-options, the default is zopetal.
-  Thanks to Cheer Xiao for the idea of making this configurable *and*
-  for the actual implementation! (Ralf)
-  WARNING: Chameleon support is highly experimental and *not* recommended for
-  production use. It has known performance issues and i18n is not yet
-  functioning. It's still under active development. Only use this feature if
-  you want to experiment with Chameleon and/or help with Roundup
-  developement. If you found a bug in Chameleon support, please report after
-  testing against latest Roundup source from the Mercurial repository.
-- issue2550678: Allow pagesize=-1 which returns all results.
-  Suggested and implemented by John Kristensen. 
-  Tested by Satchidanand Haridas. (Bernhard)
-- Allow to turn off translation of generated html options in menu method
-  of LinkHTMLProperty and MultilinkHTMLProperty -- default is
-  translation as it used to be (Ralf)
-- Sending of OpenPGP encrypted mail to all users or selected users (via
-  roles) is now working. (Ralf)
-- Add config-option "nosy" to messages_to_author setting in [nosy]
-  section of config: This will send a message to the author only
-  in the case where the author is on the nosy-list (either added
-  earlier or via the add_author setting). Current config-options
-  for this setting will send / not send to author without considering
-  the nosy list. (Ralf)
+- issue2550782: Added a new irker detector to send notifications on IRC
+  when an issue is created or messages are added. (Ezio Melotti)
+- Beta version of responsive templates using devel schema
+  and Twitter Bootstrap for styling (Pradip Caulagi)
+- pywin32 is no longer required to run on Windows (anatoly techtonik)
+- Rewritten portalocker.py logic in ctypes for Windows (anatoly techtonik)
+- Add an interface to register clearCache callbacks in roundupdb.
+  Sometimes complicated computations may require an application cache.
+  This application can now register a callback to clear the application
+  cache, because roundup knows better when to clear it (usually when a
+  transaction ends, either with rollback or with commit). The interface
+  for this is currently considered experimental. The current interface
+  is registerClearCacheCallback(self, method, param) where method is
+  called with param as the only parameter.  (Ralf Schlatterbeck)
+- Add a script to remove file-spam from a tracker, see
+  scripts/spam-remover. (Ralf Schlatterbeck)
 
 Fixed:
 
-- issue2550730: FAQ has broken link to Zope book. Reported and fixed by
-  John Rouillard.(Bernhard)
-- issue2550728: remove buggy parentheses in TAL/DummyEngine.py.
-  Reported and fixed by Ralf Hemmecke. (Bernhard)
-- issue2550715: IndexError when requesting non-existing file via http.
-  Reported and fixed by Cedric Krier. (Bernhard)
-- issue2550712: exportcsvaction errors poorly when given invalid columns.
-  Reported by Will Kahn-Greene, fixed by Cedric Krier. (Bernhard)
-- issue2550695: 'No sort or group' settings not retained when editing queries.
-  Reported and fixed by John Kristensen. Tested by Satchidanand Haridas. 
-  (Bernhard)
-- Fix matching of incoming email addresses to the alternate_addresses
-  field of a user -- this would match substrings, e.g. if the user has
-  discuss-support@example.com as an alternate email and an incoming mail
-  is addressed to support@example.com this would (wrongly) match. (Ralf)
-- issue2550729: Fix password history display for anydbm backend, thanks
-  to Ralf Hemmecke for reporting. (Ralf)
-- OpenPGP support is again working (pyme API has changed significantly) and
-  we now have a regression test. We now take care that bounce-messages
-  for incoming encrypted mails or mails where the policy dictates that
-  outgoing traffic should be encrypted is actually OpenPGP encrypted. (Ralf)
-- Ignore confirm set() fields by themselves in the absence of non-"confirm"
-  values; otherwise a bare confirm field can be used to change the a
-  password. Reported by Cam Blackwood. (Ralf)
-- Updated version of simplified Chinese message file by Cheer Xiao:
-  Corrected some mistakes, added a few more items and did some
-  formating. (Ralf)
-- Fix xmlrpc URL parsing so that passwords may contain a ':' character
-  (Ralf)
-- Be more tolerant when parsing RFC2047 encoded mail headers. Use
-  backported version of my proposed changes to
-  email.header.decode_header in http://bugs.python.org/issue1079
-  (Ralf)
-- issue2550684 Fix XSS vulnerability when username contains HTML code,
-  thanks to Thomas Arendsen Hein for reporting and patch. (Ralf)
-- issue2550711 Fix XSS vulnerability in @action parameter,
-  thanks to "om" for reporting. (Ralf)
-- issue2550535 In some cases even when keep_quoted_text=yes is
-  configured we would strip quoted sections. This hit the python
-  bug-tracker especially for python interpreter examples with leading
-  '>>>' strings. The fix is slightly different compared to the proposal
-  as this broke keep_quoted_text=no in certain cases. We also fix a bug
-  where keep_quoted_text=no would drop the last line of a non-quoted
-  section if there wasn't an empty line between the next quotes. (Ralf)
-- issue2431638 wrong registration link in bounce mail for non-registered
-  users reported *years* ago by anonymous (Ralf)
-- Fix doc/upgrading.txt which produces errors with latest docutils about
-  wrong block structure. Fix .gitignore in doc directory. Thanks to
-  Cheer Xiao for the patches. (Ralf)
-- Fix wrong execute permissions on some files, thanks to Cheer Xiao for
-  the patch. (Ralf)
-- Fix override of TemplatingUtils in instance.py, thanks to Cheer Xiao
-  for the patch. (Ralf)
-- Fix another XSS with the "otk" parameter, thanks to Jesse Ruderman for
-  reporting. (Ralf)
-- Mark cookies HttpOnly and -- if https is used -- secure. Fixes
-  issue2550689, but is untested if this really works in browsers.
-  Thanks to Joseph Myers for reporting. (Ralf)
-- Fix another XSS with the ok- and error message, see issue2550724. We
-  solve this differently from the proposals in the bug-report by not
-  allowing *any* html-tags in ok/error messages anymore. Thanks to 
-  David Benjamin for the bug-report and to Ezio Melotti for several
-  proposed fixes. (Ralf)
+- issue2550765: Don't show links in calendar that will fail.
+  Found and fixed by Cedric Krier. (Bernhard)
+- issue2550765: use <meta name="robots" content="noindex, nofollow"> in the
+  _generic.calendar.html to prevent robots to follow all the links in the
+  calendar. (Ezio Melotti)
+- "BaseException.with_traceback" is not available on Python 2, so use
+  "raise E, V, T" instead of "raise E(V).with_traceback(T)".  This change was
+  originally introduced in 74476eaac38a. (Ezio Melotti)
+- issue2550759: Trailing punctuation is no longer included when URLs are
+  converted to links. (Ezio Melotti)
+- issue2550574: Restore sample detectors removed in roundup 1.4.9
+  (Thomas Arendsen Hein)
+- Prevent AttributeError when removing all roles of a user
+  (Thomas Arendsen Hein)
+- issue2550762 Minor Documentation fix in doc/developers.txt, thanks
+  to W. Trevor King. (Bernhard Reiter)
+- issue2550766: Minor formatting issues in the docs for date properties,
+  thanks John Kristensen. (Bernhard Reiter)
+- issue2550738: Fixes for various documentation typoes,
+  thanks Nathan Russell. (John Kristensen)
+- issue2550756: Fix `oder' typo in mailer.Mailer.bounce_message docstring,
+  thanks W. Trevor King (John Kristensen)
+- Fix basic authentication: instatiating the login action would fail if
+  the user is not set. We now first set the user to anonymous and then
+  try basic authentication if enabled. (Ralf Schlatterbeck)
+- Fix xmlrpc permissions for lookup method: Allow if the key attribute
+  is either searchable or viewable, don't check id attribute (Ralf
+  Schlatterbeck)
+- Fix installation documentation (section Prerequisites) to require at
+  least python 2.5, thanks to John P. Rouillard for discovering this.
+  (committed by Ralf Schlatterbeck)
+- Fix version_check.py to require at least python 2.5 (anatoly techtonik)
+- Fixing the download button re-activating the cheeseshop plugin in the 
+  sphinx config. Thanks to Richard for the hint. (Bernhard Reiter)
+- issue2550783 devel template's schema.py permissions referenced the
+  organization property for the user, but the property is called
+  organisation. Thanks to Pradip Caulagi. (committed by John Rouillard)
+- issue2550749 - the xmlrpc interface is invoked on content type
+  and not url path. Sending any text/xml data to roundup results in
+  invoking the xml-rpc interface, but a REST or other interface could
+  also consume xml data and do something different. So require the use
+  of 'http(s)://.../xmlrpc' uri to trigger the xmlrpc interface.
+  (John Rouillard)
+- issue2550774: Remove generating documentation with rst2html, and update the
+  README.txt with how to create the html docs using sphinx, thanks Kai Storbeck
+  (John Kristensen)
+- issue2550774: Include doc/conf.py in the release tarball, so people can build
+  their own documentation in html, thanks Kai Storbeck (John Kristensen)
+- issue2550774: Update website/www/Makefile to symlink COPYING.txt so "make"
+  works again, thanks Kai Storbeck (John Kristensen)
+- issue2550760: Several improvements to the manpages
+  thanks Kai Storbeck & Bastian Kleineidam (John Kristensen)
 
 If you're upgrading from an older version of Roundup you *must* follow
 the "Software Upgrade" guidelines given in the maintenance documentation.

doc/customizing.txt

 the ``'detectors'`` directory of the Roundup distribution. If you want
 to use one, copy it to the ``'detectors'`` of your tracker instance:
 
+**irker.py**
+  This detector sends notification on IRC through an irker daemon
+  (http://www.catb.org/esr/irker/) when issues are created or messages
+  are added.  In order to use it you need to install irker, start the
+  irkerd daemon, and add an ``[irker]`` section in ``detectors/config.ini``
+  that contains a comma-separated list of channels where the messages should
+  be sent, e.g. ``channels = irc://chat.freenode.net/channelname``.
 **newissuecopy.py**
   This detector sends an email to a team address whenever a new issue is
   created. The address is hard-coded into the detector, so edit it

doc/installation.txt

 Prerequisites
 =============
 
-Roundup requires Python 2.3 or newer (but not Python 3) with a functioning
+Roundup requires Python 2.5 or newer (but not Python 3) with a functioning
 anydbm module. Download the latest version from http://www.python.org/.
 It is highly recommended that users install the latest patch version
 of python as these contain many fixes to serious bugs.
 installed for Roundup installation to work. Debian and derivatives, are
 known to require this.
 
-If you're on windows, you will either need to be using the ActiveState python
-distribution (at http://www.activestate.com/Products/ActivePython/), or you'll
-have to install the win32all package separately (get it from
-http://starship.python.net/crew/mhammond/win32/).
-
 
 Optional Components
 ===================
   configured, you can require email to be cryptographically signed
   before roundup will allow it to make modifications to issues.
 
+Windows Service
+  You can run Roundup as a Windows service if pywin32_ is installed.
+
 .. _Xapian: http://xapian.org/
 .. _pytz: http://www.python.org/pypi/pytz
 .. _Olson tz database: http://www.twinsun.com/tz/tz-link.htm
 .. _pyopenssl: http://pyopenssl.sourceforge.net
 .. _pyme: http://pyme.sourceforge.net
+.. _pywin32: http://pypi.python.org/pypi/pywin32
 
 
 Getting Roundup
 
 Download the latest version from http://www.roundup-tracker.org/.
 
-If you're using WinZIP's "classic" interface, make sure the "Use
-folder names" check box is checked before you extract the files.
-
-
 For The Really Impatient
 ========================
 
-If you just want to give Roundup a whirl Right Now, then simply run
-``roundup-demo``.
+If you just want to give Roundup a whirl Right Now, then simply unpack
+and run ``demo.py`` (it will be available as ``roundup-demo`` script
+after installation).
 
 This will set up a simple demo tracker on your machine. [1]_
 When it's done, it'll print out a URL to point your web browser at

doc/postgresql.txt

 To use PostgreSQL as backend for storing roundup data, you should
 additionally install:
 
-1. PostgreSQL 7.x - http://www.postgresql.org/
+1. PostgreSQL 8.x or higher - http://www.postgresql.org/
 
 2. The psycopg python interface to PostgreSQL:
 
      http://initd.org/software/initd/psycopg
 
-   It is recommended that you use at least version 1.1.21
-
 
 Running the PostgreSQL unit tests
 =================================

doc/upgrading.txt

 ``share/roundup/templates/classic/html/_generic.calendar.html``; if you did,
 you can add the tag manually.  See issue2550765 and changeset a099ff2ceff3.
 
+If you are using the xml-rpc interface, there is a change
+  in accessing it. You can not send text/xml data to any
+  roundup url and get a response, you must use the /xmlrpc
+  url. For example, if you used to send your xmlrpc request to:
+
+   http://myroundup.com/roundup
+
+  you need to change the url to read:
+
+   http://myroundup.com/roundup/xmlrpc
+
+  to invoke the xmlrpc handler. This allows us to send xml
+  data to roundup for other handlers (e.g. REST, SOAP ...)
+  in the future.
 
 Migrating from 1.4.19 to 1.4.20
 ===============================
 limiting. The XML-RPC frontend provides the ability to execute a limited subset
 of commands similar to those found in roundup-admin from remote machines. 
 
-roundup-xmlrpc-server
+There are two ways to access the xmlrpc interface:
+
+  stand alone roundup-xmlrpc-server
+
+  access via the roundup server
+  
+  
+stand alone roundup-xmlrpc-server
 ---------------------
-The Roundup XML-RPC server must be started before remote clients can access the
+The Roundup XML-RPC standalone server must be started before remote clients can access the
 tracker via XML-RPC. ``roundup-xmlrpc-server`` is installed in the scripts
 directory alongside ``roundup-server`` and roundup-admin``. When invoked, the
 location of the tracker instance must be specified.
 The default port is ``8000``. An alternative port can be specified with the
 ``--port`` switch.
 
+accessing via roundup server
+----------------------------
+In addition to running a stand alone server described above, the
+xmlrpc service is available from the roundup HTTP server. Access it by
+sending text/xml data to the URL for the roundup tracker with the last
+component of the url set to 'xmlrpc'.
+
 security consideration
 ======================
 Note that the current ``roundup-xmlrpc-server`` implementation does not
         []
         >>> roundup_server.lookup('user','admin')
         '1'
+
+If you are accessing the interface via the roundup HTTP server, a url
+similar to:
+
+  http://username:password@localhost:8000/tracker/xmlrpc
+
+should be used.

roundup/__init__.py

 '''
 __docformat__ = 'restructuredtext'
 
-__version__ = '1.4.20'
+__version__ = '1.4.21'
 
 # vim: set filetype=python ts=4 sw=4 et si

roundup/anypy/TODO.txt

 Python compatiblity TODO
 ~~~~~~~~~~~~~~~~~~~~~~~~
 
-- the popen2 module is deprecated as of Python 2.6;
-  the subprocess module is available since Python 2.4,
-  thus a roundup.anypy.subprocess_ module is needed
-
-# vim: si
+Remove sets_ included for Python 2.3 compatibility.

roundup/backends/__init__.py

         return vars[name]
     # import the backend module
     module_name = 'back_%s' % name
-    try:
-        module = __import__(module_name, vars)
-    except:
-        # import failed, but in versions prior to 2.4, a (broken)
-        # module is left in sys.modules and package globals;
-        # subsequent imports would succeed and get the broken module.
-        # This no longer happens in Python 2.4 and later.
-        if sys.version_info < (2, 4):
-            del sys.modules['.'.join((__name__, module_name))]
-            del vars[module_name]
-        raise
-    else:
-        vars[name] = module
-        return module
+    module = __import__(module_name, vars)
+    vars[name] = module
+    return module
 
 def have_backend(name):
     '''Is backend "name" available?'''

roundup/backends/indexer_common.py

 import re
-# Python 2.3 ... 2.6 compatibility:
-from roundup.anypy.sets_ import set
 
 from roundup import hyperdb
 

roundup/backends/indexer_rdbms.py

 propname, itemid) instances.
 """
 import re
-# Python 2.3 ... 2.6 compatibility:
-from roundup.anypy.sets_ import set
 
 from roundup.backends.indexer_common import Indexer as IndexerBase
 

roundup/backends/portalocker.py

+#!/usr/bin/env python
+#
 # portalocker.py - Cross-platform (posix/nt) API for flock-style file locking.
-#                  Requires python 1.5.2 or better.
-
-"""Cross-platform (posix/nt) API for flock-style file locking.
+#
+# http://code.activestate.com/recipes/65203-portalocker-cross-platform-posixnt-api-for-flock-s/
+#
+"""
+Cross-platform (posix/nt) API for flock-style file locking.
 
 Synopsis::
 
 that accompanies the win32 modules.
 
 :Author: Jonathan Feinberg <jdf@pobox.com>
-:Version: Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp 
-          **un-cvsified by richard so the version doesn't change**
+
+Roundup Changes
+---------------
+2012-11-28 (anatoly techtonik)
+   - Ported to ctypes
+   - Dropped support for Win95, Win98 and WinME
+   - Added return result
 """
+
 __docformat__ = 'restructuredtext'
 
 import os
 
 if os.name == 'nt':
-    import win32con
-    import win32file
-    import pywintypes
-    LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
-    LOCK_SH = 0 # the default
-    LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
-    # is there any reason not to reuse the following structure?
-    __overlapped = pywintypes.OVERLAPPED()
+    import msvcrt
+    from ctypes import *
+    from ctypes.wintypes import BOOL, DWORD, HANDLE
+
+    LOCK_SH = 0    # the default
+    LOCK_NB = 0x1  # LOCKFILE_FAIL_IMMEDIATELY
+    LOCK_EX = 0x2  # LOCKFILE_EXCLUSIVE_LOCK
+
+    # --- the code is taken from pyserial project ---
+    #
+    # detect size of ULONG_PTR 
+    def is_64bit():
+        return sizeof(c_ulong) != sizeof(c_void_p)
+    if is_64bit():
+        ULONG_PTR = c_int64
+    else:
+        ULONG_PTR = c_ulong
+    PVOID = c_void_p
+
+    # --- Union inside Structure by stackoverflow:3480240 ---
+    class _OFFSET(Structure):
+        _fields_ = [
+            ('Offset', DWORD),
+            ('OffsetHigh', DWORD)]
+
+    class _OFFSET_UNION(Union):
+        _anonymous_ = ['_offset']
+        _fields_ = [
+            ('_offset', _OFFSET),
+            ('Pointer', PVOID)]
+
+    class OVERLAPPED(Structure):
+        _anonymous_ = ['_offset_union']
+        _fields_ = [
+            ('Internal', ULONG_PTR),
+            ('InternalHigh', ULONG_PTR),
+            ('_offset_union', _OFFSET_UNION),
+            ('hEvent', HANDLE)]
+
+    LPOVERLAPPED = POINTER(OVERLAPPED)
+
+    # --- Define function prototypes for extra safety ---
+    LockFileEx = windll.kernel32.LockFileEx
+    LockFileEx.restype = BOOL
+    LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
+    UnlockFileEx = windll.kernel32.UnlockFileEx
+    UnlockFileEx.restype = BOOL
+    UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]
+            
 elif os.name == 'posix':
     import fcntl
+    LOCK_SH = fcntl.LOCK_SH  # shared lock
+    LOCK_NB = fcntl.LOCK_NB  # non-blocking
     LOCK_EX = fcntl.LOCK_EX
-    LOCK_SH = fcntl.LOCK_SH
-    LOCK_NB = fcntl.LOCK_NB
 else:
     raise RuntimeError("PortaLocker only defined for nt and posix platforms")
 
 if os.name == 'nt':
-    # eugh, we want 0xffff0000 here, but python 2.3 won't let us :(
-    FFFF0000 = -65536
     def lock(file, flags):
-        hfile = win32file._get_osfhandle(file.fileno())
-        # LockFileEx is not supported on all Win32 platforms (Win95, Win98,
-        # WinME).
-        # If it's not supported, win32file will raise an exception.
-        # Try LockFileEx first, as it has more functionality and handles
-        # blocking locks more efficiently.
-        try:
-            win32file.LockFileEx(hfile, flags, 0, FFFF0000, __overlapped)
-        except win32file.error, e:
-            import winerror
-            # Propagate upwards all exceptions other than not-implemented.
-            if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
-                raise e
-            
-            # LockFileEx is not supported. Use LockFile.
-            # LockFile does not support shared locking -- always exclusive.
-            # Care: the low/high length params are reversed compared to
-            # LockFileEx.
-            if not flags & LOCK_EX:
-                import warnings
-                warnings.warn("PortaLocker does not support shared "
-                    "locking on Win9x", RuntimeWarning)
-            # LockFile only supports immediate-fail locking.
-            if flags & LOCK_NB:
-                win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
-            else:
-                # Emulate a blocking lock with a polling loop.
-                import time
-                while 1:
-                    # Attempt a lock.
-                    try:
-                        win32file.LockFile(hfile, 0, 0, FFFF0000, 0)
-                        break
-                    except win32file.error, e:
-                        # Propagate upwards all exceptions other than lock
-                        # violation.
-                        if e[0] != winerror.ERROR_LOCK_VIOLATION:
-                            raise e
-                    # Sleep and poll again.
-                    time.sleep(0.1)
-        # TODO: should this return the result of the lock?
-                    
+        """ Return True on success, False otherwise """
+        hfile = msvcrt.get_osfhandle(file.fileno())
+        overlapped = OVERLAPPED()
+        if LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped)):
+            return True
+        else:
+            return False
+
     def unlock(file):
-        hfile = win32file._get_osfhandle(file.fileno())
-        # UnlockFileEx is not supported on all Win32 platforms (Win95, Win98,
-        # WinME).
-        # If it's not supported, win32file will raise an api_error exception.
-        try:
-            win32file.UnlockFileEx(hfile, 0, FFFF0000, __overlapped)
-        except win32file.error, e:
-            import winerror
-            # Propagate upwards all exceptions other than not-implemented.
-            if e[0] != winerror.ERROR_CALL_NOT_IMPLEMENTED:
-                raise e
-            
-            # UnlockFileEx is not supported. Use UnlockFile.
-            # Care: the low/high length params are reversed compared to
-            # UnLockFileEx.
-            win32file.UnlockFile(hfile, 0, 0, FFFF0000, 0)
+        hfile = msvcrt.get_osfhandle(file.fileno())
+        overlapped = OVERLAPPED()
+        if UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped)):
+            return True
+        else:
+            return False
 
 elif os.name =='posix':
     def lock(file, flags):
-        fcntl.flock(file.fileno(), flags)
-        # TODO: should this return the result of the lock?
+        if fcntl.flock(file.fileno(), flags) == 0:
+            return True
+        else:
+            return False
 
     def unlock(file):
-        fcntl.flock(file.fileno(), fcntl.LOCK_UN)
+        if fcntl.flock(file.fileno(), fcntl.LOCK_UN) == 0:
+            return True
+        else:
+            return False
 
 if __name__ == '__main__':
     from time import time, strftime, localtime

roundup/cgi/client.py

         """ Wrap the real main in a try/finally so we always close off the db.
         """
         try:
-            if self.env.get('CONTENT_TYPE') == 'text/xml':
+            if self.env.get('CONTENT_TYPE') == 'text/xml' and self.path == 'xmlrpc':
                 self.handle_xmlrpc()
             else:
                 self.inner_main()
                         pass
                     username, password = decoded.split(':', 1)
                     try:
+                        # Current user may not be None, otherwise
+                        # instatiation of the login action will fail.
+                        # So we set the user to anonymous first.
+                        self.make_user_anonymous()
                         login = self.get_action_class('login')(self)
                         login.verifyLogin(username, password)
                     except LoginError, err:

roundup/cgi/templating.py

         if direction == 'ascending':
             l.reverse()
 
-        l[0:0] = ['<table class="history">'
+        l[0:0] = ['<table class="history table table-condensed table-striped">'
              '<tr><th colspan="4" class="header">',
              self._('History'),
              '</th></tr><tr>',

roundup/configuration.py

         (Option, "template_engine", "zopetal",
             "Templating engine to use.\n"
             "Possible values are 'zopetal' for the old TAL engine\n"
-            "ported from Zope, or 'chameleon' for Chamaleon."),
+            "ported from Zope, or 'chameleon' for Chameleon."),
         (FilePathOption, "templates", "html",
             "Path to the HTML templates directory."),
         (NullableFilePathOption, "static_files", "",

roundup/hyperdb.py

 
 # standard python modules
 import os, re, shutil, weakref
-# Python 2.3 ... 2.6 compatibility:
-from roundup.anypy.sets_ import set
 
 # roundup modules
 import date, password

roundup/password.py

     if off == 0:
         return b64decode(data, "./")
     elif off == 1:
-        raise ValueError("invalid bas64 input")
+        raise ValueError("Invalid base64 input")
     elif off == 2:
         return b64decode(data + "==", "./")
     else:
     elif scheme == 'plaintext':
         s = plaintext
     else:
-        raise PasswordValueError, 'unknown encryption scheme %r'%scheme
+        raise PasswordValueError, 'Unknown encryption scheme %r'%scheme
     return s
 
 def generatePassword(length=8):
             # currently plaintext - encrypt
             self.setPassword(encrypted, scheme, config=config)
         if strict and self.scheme not in self.known_schemes:
-            raise PasswordValueError, "unknown encryption scheme: %r" % (self.scheme,)
+            raise PasswordValueError, "Unknown encryption scheme: %r" % (self.scheme,)
 
     def setPassword(self, plaintext, scheme=None, config=None):
         """Sets encrypts plaintext."""
     assert 'not sekrit' != p
 
     # crypt
-    p = Password('sekrit', 'crypt')
-    assert p == 'sekrit'
-    assert p != 'not sekrit'
-    assert 'sekrit' == p
-    assert 'not sekrit' != p
+    if crypt:  # not available on Windows
+        p = Password('sekrit', 'crypt')
+        assert p == 'sekrit'
+        assert p != 'not sekrit'
+        assert 'sekrit' == p
+        assert 'not sekrit' != p
 
     # PBKDF2 - low level function
     from binascii import unhexlify

roundup/version_check.py

 #!/usr/bin/env python
-#
-# 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.
 
-"""Enforces the minimum Python version that Roundup requires.
-"""
-__docformat__ = 'restructuredtext'
+# Roundup requires Python 2.5+ as mentioned in doc\installation.txt
+VERSION_NEEDED = (2,5)
 
 import sys
-if not hasattr(sys, 'version_info') or sys.version_info[:3] < (2,1,1):
+if sys.version_info < VERSION_NEEDED:
     print "Content-Type: text/plain\n"
-    print "Roundup requires Python 2.1.1 or newer."
+    print "Roundup requires Python %s.%s or newer." % VERSION_NEEDED
     sys.exit(0)
-
-# vim: set filetype=python ts=4 sw=4 et si

roundup/xmlrpc.py

         cl = self.db.getclass(classname)
         uid = self.db.getuid()
         prop = cl.getkey()
-        check = self.db.security.hasSearchPermission
-        if not check(uid, classname, 'id') or not check(uid, classname, prop):
-            raise Unauthorised('Permission to search %s denied'%classname)
+        search = self.db.security.hasSearchPermission
+        access = self.db.security.hasPermission
+        if (not search(uid, classname, prop)
+           and not access('View', uid, classname, prop)):
+           raise Unauthorised('Permission to lookup %s denied'%classname)
         return cl.lookup(key)
 
     def display(self, designator, *properties):
         gc.set_debug(gcdebug)
 
     if build:
-        # Python 2.3 is more sane in its non -q output
-        if sys.hexversion >= 0x02030000:
-            qflag = ""
-        else:
-            qflag = "-q"
-        cmd = sys.executable + " setup.py " + qflag + " build"
+        cmd = sys.executable + " setup.py build"
         if build_inplace:
             cmd += "_ext -i"
         if VERBOSE:

scripts/import_sf.py

 """
 
 import sys, os, csv, time, urllib2, httplib, mimetypes, urlparse
-# Python 2.3 ... 2.6 compatibility:
-from roundup.anypy.sets_ import set
 
 try:
     import cElementTree as ElementTree
 #! /usr/bin/env python
+# -*- coding: utf-8 -*-
 #
 # 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
 from roundup.dist.command.build import build, list_message_files
 from roundup.dist.command.bdist_rpm import bdist_rpm
 from roundup.dist.command.install_lib import install_lib
-from distutils.core import setup
+
+try:
+    from setuptools import setup
+except ImportError:
+    from distutils.core import setup
 
 import sys, os
 from glob import glob
     templates = [t['path']
                  for t in listTemplates('share/roundup/templates').values()]
     for tdir in templates:
-        for idir in '. detectors extensions html'.split():
+        for idir in '. detectors extensions html static'.split():
             data_files.append(include(os.path.join(tdir, idir), '*'))
 
     # add message files
                        'Intended Audience :: End Users/Desktop',
                        'Intended Audience :: Developers',
                        'Intended Audience :: System Administrators',
-                       'License :: OSI Approved :: Python Software Foundation License',
+                       'License :: OSI Approved :: MIT License',
                        'Operating System :: MacOS :: MacOS X',
                        'Operating System :: Microsoft :: Windows',
                        'Operating System :: POSIX',

share/man/man1/roundup-admin.1

 \fB-i\fP \fIinstance home\fP
 specify the issue tracker "home directory" to administer
 .TP
-\fB-u\fP
-the user[:password] to use for commands
+\fB-u\fP \fIuser\fP[\fB:\fP\fIpassword\fP]
+the user and password to use for commands
 .TP
 \fB-c\fP
-when outputting lists of data, just comma-separate them
+When outputting lists of data, comma-separate them. Same as
+\fB-S ","\fP.
+.TP
+\fB-S\fP \fIstring\fP
+When outputting lists of data, separate items with given string.
+.TP
+\fB-s\fP
+When outputting lists of data, space-separate them. Same as
+\fB-S " "\fP.
 .SH FURTHER HELP
  roundup-admin -h
  roundup-admin help                       -- this help

share/man/man1/roundup-mailgw.1

 .SH NAME
 roundup-mailgw \- mail gateway for roundup
 .SH SYNOPSIS
-\fBroundup-mailgw\fP \fI<instance home>\fP [\fImethod\fP]
+\fBroundup-mailgw\fP \fIinstance_home\fP [\fImethod\fP]
 .SH OPTIONS
 .TP
+\fB-v\fP
+Print version and exit.
+.TP
 \fB-C\fP \fIhyperdb class\fP
 specify a tracker class - one of msg (the default), issue, file, user - to
 manipulate with -S options
 .TP
-\fB-S\fP \fIproperty=value[;property=value] pairs\fP
+\fB-S\fP \fIproperty\fP\fB=\fP\fIvalue\fP[\fB;\fP\fIproperty\fP\fB=\fP\fIvalue\fP] \fIpairs\fP
 specify the values to set on the class specified by -C using the same
 format as the Subject line property manipulations
 .SH DESCRIPTION
 In the third case, the gateway reads all messages from the POP server
 specified and submits each in turn to the roundup.mailgw module. The
 server is specified as:
- \fIpop username:password@server\fP
+ \fBpop\fP \fIusername\fP\fB:\fP\fIpassword\fP\fB@\fP\fIserver\fP
 .br
 The username and password may be omitted:
- \fIpop username@server\fP
- \fIpop server\fP
+ \fBpop\fP \fIusername\fP\fB@\fP\fIserver\fP
+ \fBpop\fP \fIserver\fP
 .br
-are both valid.
+are both valid. The username and/or password will be prompted for if
+not supplied on the command-line.
 
 \fBAPOP\fP
+.br
 Same as POP, but using Authenticated POP:
- \fIapop username:password@server\fP
+ \fBapop\fP \fIusername\fP\fB:\fP\fIpassword\fP\fB@\fP\fIserver\fP
+
+\fBIMAP\fP
+.br
+Connect to an IMAP server. This supports the same notation as that of
+POP mail.
+ \fBimap\fP \fIusername\fP\fB:\fP\fIpassword\fP\fB@\fP\fIserver\fP
+.br
+It also allows you to specify a specific mailbox other than INBOX using
+this format:
+ \fBimap\fP \fIusername\fP\fB:\fP\fIpassword\fP\fB@\fP\fIserver mailbox\fP
+
+\fBIMAPS\fP
+.br
+Connect to an IMAP server over ssl.
+This supports the same notation as IMAP.
+ \fBimaps\fP \fIusername\fP\fB:\fP\fIpassword\fP\fB@\fP\fIserver\fP [\fImailbox\fP]
 .SH AUTHOR
 This manpage was written by Bastian Kleineidam
 <calvin@debian.org> for the Debian distribution of roundup.

share/man/man1/roundup-server.1

 Use options read from the configuration file (see below).
 .TP
 \fB-n\fP \fIhostname\fP
-Sets the host name.
+Sets the host name or IP address to listen on
 .TP
 \fB-p\fP \fIport\fP
-Sets the port to listen on.
+Sets the port to listen on (default: 8080).
 .TP
 \fB-d\fP \fIfile\fP
 Daemonize, and write the server's PID to the nominated file.
 Sets a filename containing the PEM file to use for SSL. If left blank, a
 temporary self-signed certificate will be used.
 .TP
+\fB-N\fP
+Log client machine names instead of IP addresses (much slower).
+.TP
+\fB-u\fP \fIUID\fP
+Runs the Roundup web server as this UID.
+.TP
+\fB-g\fP \fIGID\fP
+Runs the Roundup web server as this GID.
+.TP
+\fB-d\fP \fIPIDfile\fP
+Run the server in the background and write the server's PID
+to the file indicated by PIDfile. The -l option \fBmust\fP be
+specified if -d is used.
+.TP
+\fB-v\fP
+Print version and exit.
+.TP
 \fB-h\fP
-print help
+Print help and exit.
 .TP
 \fBname=\fP\fItracker home\fP
 Sets the tracker home(s) to use. The \fBname\fP variable is how the tracker is

share/roundup/templates/classic/detectors/nosyreaction.py

 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
 
-# Python 2.3 ... 2.6 compatibility:
-from roundup.anypy.sets_ import set
-
 from roundup import roundupdb, hyperdb
 
 def nosyreaction(db, cl, nodeid, oldvalues):

share/roundup/templates/devel/schema.py

     description="User is allowed to edit their own user details",
     properties=('username', 'password',
                 'address', 'realname',
-                'phone', 'organization',
+                'phone', 'organisation',
                 'alternate_addresses',
                 'queries',
                 'timezone')) # Note: 'roles' excluded - users should not be able to edit their own roles. 

share/roundup/templates/responsive/TEMPLATE-INFO.txt

+Name: responsive
+Description: This issue tracker uses the same schema as devel.
+            The difference between devel and responsive templates
+            is the use of Twitter bootstrap (http://twitter.github.com/bootstrap/)
+            in templates and HTML5 markup.
+	    Make sure the "static_files" setting in your config.ini of your
+            instance is set to the directory where the static files live
+            (the subdirectory "static" in the default of the template).
+Intended-For: Developers

share/roundup/templates/responsive/config.ini

+# Roundup issue tracker configuration file
+# Autogenerated at Fri Nov 17 16:59:49 2006
+
+# WARNING! Following options need adjustments:
+#  [mail]: domain, host
+#  [tracker]: web
+
+[main]
+
+# Database directory path.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: db
+database = db
+
+# Path to the HTML templates directory.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: html
+templates = html
+
+# Path to directory holding additional static files
+# available via Web UI.  This directory may contain
+# sitewide images, CSS stylesheets etc. and is searched
+# for these files prior to the TEMPLATES directory
+# specified above.  If this option is not set, all static
+# files are taken from the TEMPLATES directory
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: 
+static_files = static
+
+# Email address that roundup will complain to if it runs into trouble.
+# Default: roundup-admin
+admin_email = roundup-admin
+
+# 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.
+# Default: roundup-admin
+dispatcher_email = roundup-admin
+
+# 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>
+# Default: 
+email_from_tag = 
+
+# Roles that a user gets when they register with Web User Interface.
+# This is a comma-separated string of role names (e.g. 'Admin,User').
+# Default: User
+new_web_user_roles = User
+
+# Roles that a user gets when they register with Email Gateway.
+# This is a comma-separated string of role names (e.g. 'Admin,User').
+# Default: User
+new_email_user_roles = User
+
+# Send error message emails to the dispatcher, user, or both?
+# The dispatcher is configured using the DISPATCHER_EMAIL setting.
+# Default: user
+error_messages_to = user
+
+# 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.
+# Allowed values: html4, xhtml
+# Default: html4
+html_version = xhtml
+
+# Default timezone offset, applied when user's timezone is not set.
+# If pytz module is installed, value may be any valid
+# timezone specification (e.g. EET or Europe/Warsaw).
+# If pytz is not installed, value must be integer number
+# giving local timezone offset from UTC in hours.
+# Default: UTC
+timezone = UTC
+
+# Register new users instantly, or require confirmation via
+# email?
+# Allowed values: yes, no
+# Default: no
+instant_registration = no
+
+# Offer registration confirmation by email or only through the web?
+# Allowed values: yes, no
+# Default: yes
+email_registration_confirmation = yes
+
+# Additional stop-words for the full-text indexer specific to
+# your tracker. See the indexer source for the default list of
+# stop-words (eg. A,AND,ARE,AS,AT,BE,BUT,BY, ...)
+# Allowed values: comma-separated list of words
+# Default: 
+indexer_stopwords = 
+
+# Defines the file creation mode mask.
+# Default: 02
+umask = 02
+
+[tracker]
+
+# A descriptive name for your roundup instance.
+# Default: Roundup issue tracker
+name = Roundup tracker
+
+# 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.
+# Default: NO DEFAULT
+web = 
+
+# Email address that mail to roundup should go to.
+# Default: issue_tracker
+email = issue_tracker
+
+# Default locale name for this tracker.
+# If this option is not set, the language is determined
+# by OS environment variable LANGUAGE, LC_ALL, LC_MESSAGES,
+# or LANG, in that order of preference.
+# Default: 
+language = 
+
+[web]
+
+# Whether to use HTTP Basic Authentication, if present.
+# Roundup will use either the REMOTE_USER or HTTP_AUTHORIZATION
+# variables supplied by your web server (in that order).
+# Set this option to 'no' if you do not wish to use HTTP Basic
+# Authentication in your web interface.
+# Allowed values: yes, no
+# Default: yes
+http_auth = yes
+
+# Whether to use HTTP Accept-Language, if present.
+# Browsers send a language-region preference list.
+# It's usually set in the client's browser or in their
+# Operating System.
+# Set this option to 'no' if you want to ignore it.
+# Allowed values: yes, no
+# Default: yes
+use_browser_language = no
+
+# Setting this option makes Roundup display error tracebacks
+# in the user's browser rather than emailing them to the
+# tracker admin.
+# Allowed values: yes, no
+# Default: no
+debug = no
+
+# Settings in this section are used by Postgresql and MySQL backends only
+[rdbms]
+
+# Name of the database to use.
+# Default: roundup
+name = roundup_roundup_tracker
+
+# Database server host.
+# Default: localhost
+host = localhost
+
+# TCP port number of the database server.
+# Postgresql usually resides on port 5432 (if any),
+# for MySQL default port number is 3306.
+# Leave this option empty to use backend default
+# Default: 
+port = 
+
+# Database user name that Roundup should use.
+# Default: roundup
+user = roundup
+
+# Database user password.
+# Default: roundup
+password = roundup
+
+# Name of the MySQL defaults file.
+# Only used in MySQL connections.
+# Default: ~/.my.cnf
+read_default_file = ~/.my.cnf
+
+# Name of the group to use in the MySQL defaults file (.my.cnf).
+# Only used in MySQL connections.
+# Default: roundup
+read_default_group = roundup
+
+[logging]
+
+# Path to configuration file for standard Python logging module.
+# If this option is set, logging configuration is loaded
+# from specified file; options 'filename' and 'level'
+# in this section are ignored.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: 
+config = 
+
+# Log file name for minimal logging facility built into Roundup.
+# If no file name specified, log messages are written on stderr.
+# If above 'config' option is set, this option has no effect.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: 
+filename = 
+
+# Minimal severity level of messages written to log file.
+# If above 'config' option is set, this option has no effect.
+# Allowed values: DEBUG, INFO, WARNING, ERROR
+# Default: ERROR
+level = ERROR
+
+# Outgoing email options.
+# Used for nozy messages and approval requests
+[mail]
+
+# Domain name used for email addresses.
+# Default: NO DEFAULT
+#domain = NO DEFAULT
+domain = psf.upfronthosting.co.za
+
+# SMTP mail host that roundup will use to send mail
+# Default: NO DEFAULT
+#host = NO DEFAULT
+host = localhost
+
+# SMTP login name.
+# Set this if your mail host requires authenticated access.
+# If username is not empty, password (below) MUST be set!
+# Default: 
+username = 
+
+# SMTP login password.
+# Set this if your mail host requires authenticated access.
+# Default: NO DEFAULT
+#password = NO DEFAULT
+
+# If your SMTP mail host provides or requires TLS
+# (Transport Layer Security) then set this option to 'yes'.
+# Allowed values: yes, no
+# Default: no
+tls = no
+
+# If TLS is used, you may set this option to the name
+# of a PEM formatted file that contains your private key.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: 
+tls_keyfile = 
+
+# If TLS is used, you may set this option to the name
+# of a PEM formatted certificate chain file.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: 
+tls_certfile = 
+
+# 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).
+# Default: utf-8
+charset = utf-8
+
+# Setting this option makes Roundup to write all outgoing email
+# messages to this file *instead* of sending them.
+# This option has the same effect as environment variable SENDMAILDEBUG.
+# Environment variable takes precedence.
+# The path may be either absolute or relative
+# to the directory containig this config file.
+# Default: 
+#debug = /home/roundup/outgoing-mail
+debug = 
+
+# Roundup Mail Gateway options
+[mailgw]
+
+# Keep email citations when accepting messages.
+# Setting this to "no" strips out "quoted" text from the message.
+# Signatures are also stripped.
+# Allowed values: yes, no
+# Default: yes
+keep_quoted_text = yes
+
+# Preserve the email body as is - that is,
+# keep the citations _and_ signatures.
+# Allowed values: yes, no
+# Default: no
+leave_body_unchanged = no
+
+# Default class to use in the mailgw
+# if one isn't supplied in email subjects.
+# To disable, leave the value blank.
+# Default: issue
+default_class = issue
+
+# Default locale name for the tracker mail gateway.
+# If this option is not set, mail gateway will use
+# the language of the tracker instance.
+# Default: 
+language = 
+
+# Controls the parsing of the [prefix] on subject
+# lines in incoming emails. "strict" will return an
+# error to the sender if the [prefix] is not recognised.
+# "loose" will attempt to parse the [prefix] but just
+# pass it through as part of the issue title if not
+# recognised. "none" will always pass any [prefix]
+# through as part of the issue title.
+# Default: strict
+subject_prefix_parsing = strict
+
+# Controls the parsing of the [suffix] on subject
+# lines in incoming emails. "strict" will return an
+# error to the sender if the [suffix] is not recognised.
+# "loose" will attempt to parse the [suffix] but just
+# pass it through as part of the issue title if not
+# recognised. "none" will always pass any [suffix]
+# through as part of the issue title.
+# Default: strict
+subject_suffix_parsing = strict
+
+# Defines the brackets used for delimiting the prefix and 
+# suffix in a subject line. The presence of "suffix" in
+# the config option name is a historical artifact and may
+# be ignored.
+# Default: []
+subject_suffix_delimiters = []
+
+# Controls matching of the incoming email subject line
+# against issue titles in the case where there is no
+# designator [prefix]. "never" turns off matching.
+# "creation + interval" or "activity + interval"
+# will match an issue for the interval after the issue's
+# creation or last activity. The interval is a standard
+# Roundup interval.
+# Default: always
+subject_content_match = always
+
+# Nosy messages sending
+[nosy]
+
+# Send nosy messages to the author of the message.
+# Allowed values: yes, no, new
+# Default: no
+messages_to_author = yes
+
+# Where to place the email signature.
+# Allowed values: top, bottom, none
+# Default: bottom
+signature_position = bottom
+
+# 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.
+# 
+# Allowed values: yes, no, new
+# Default: new
+add_author = yes
+
+# 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.
+# 
+# Allowed values: yes, no, new
+# Default: new
+add_recipients = new
+
+# Controls the email sending from the nosy reactor. If
+# "multiple" then a separate email is sent to each
+# recipient. If "single" then a single email is sent with
+# each recipient as a CC address.
+# Default: single
+email_sending = multiple

share/roundup/templates/responsive/detectors/messagesummary.py

+from roundup.mailgw import parseContent
+
+def summarygenerator(db, cl, nodeid, newvalues):
+    ''' If the message doesn't have a summary, make one for it.
+    '''
+    if newvalues.has_key('summary') or not newvalues.has_key('content'):
+        return
+
+    summary, content = parseContent(newvalues['content'], config=db.config)
+    newvalues['summary'] = summary
+
+
+def init(db):
+    # fire before changes are made
+    db.msg.audit('create', summarygenerator)
+
+# vim: set filetype=python ts=4 sw=4 et si
+#SHA: 538f90cb7f4eb63f77eca252b87afbe037d29c48

share/roundup/templates/responsive/detectors/no_texthtml.py

+
+def audit_html_files(db, cl, nodeid, newvalues):
+    if newvalues.has_key('type') and newvalues['type'] == 'text/html':
+        newvalues['type'] = 'text/plain'
+    
+
+def init(db):
+    db.file.audit('set', audit_html_files)
+    db.file.audit('create', audit_html_files)

share/roundup/templates/responsive/detectors/nosyreaction.py

+from roundup.anypy.sets_ import set
+
+from roundup import roundupdb, hyperdb
+
+def nosyreaction(db, cl, nodeid, oldvalues):
+    ''' A standard detector is provided that watches for additions to the
+        "messages" property.
+        
+        When a new message is added, the detector sends it to all the users on
+        the "nosy" list for the issue that are not already on the "recipients"
+        list of the message.
+        
+        Those users are then appended to the "recipients" property on the
+        message, so multiple copies of a message are never sent to the same
+        user.
+        
+        The journal recorded by the hyperdatabase on the "recipients" property
+        then provides a log of when the message was sent to whom. 
+    '''
+    # send a copy of all new messages to the nosy list
+    for msgid in determineNewMessages(cl, nodeid, oldvalues):
+        try:
+            cl.nosymessage(nodeid, msgid, oldvalues)
+        except roundupdb.MessageSendError, message:
+            raise roundupdb.DetectorError, message
+
+def determineNewMessages(cl, nodeid, oldvalues):
+    ''' Figure a list of the messages that are being added to the given
+        node in this transaction.
+    '''
+    messages = []
+    if oldvalues is None:
+        # the action was a create, so use all the messages in the create
+        messages = cl.get(nodeid, 'messages')
+    elif oldvalues.has_key('messages'):
+        # the action was a set (so adding new messages to an existing issue)
+        m = {}
+        for msgid in oldvalues['messages']:
+            m[msgid] = 1
+        messages = []
+        # figure which of the messages now on the issue weren't there before
+        for msgid in cl.get(nodeid, 'messages'):
+            if not m.has_key(msgid):
+                messages.append(msgid)
+    return messages
+
+def updatenosy(db, cl, nodeid, newvalues):
+    '''Update the nosy list for changes to the assignedto
+    '''
+    # nodeid will be None if this is a new node
+    current_nosy = set()
+    if nodeid is None:
+        ok = ('new', 'yes')
+    else:
+        ok = ('yes',)
+        # old node, get the current values from the node if they haven't
+        # changed
+        if not newvalues.has_key('nosy'):
+            nosy = cl.get(nodeid, 'nosy')
+            for value in nosy:
+                current_nosy.add(value)
+
+    # if the nosy list changed in this transaction, init from the new value
+    if newvalues.has_key('nosy'):
+        nosy = newvalues.get('nosy', [])
+        for value in nosy:
+            if not db.hasnode('user', value):
+                continue
+            current_nosy.add(value)
+
+    new_nosy = set(current_nosy)
+
+    # add assignedto(s) to the nosy list
+    if newvalues.has_key('assignedto') and newvalues['assignedto'] is not None:
+        propdef = cl.getprops()
+        if isinstance(propdef['assignedto'], hyperdb.Link):
+            assignedto_ids = [newvalues['assignedto']]
+        elif isinstance(propdef['assignedto'], hyperdb.Multilink):
+            assignedto_ids = newvalues['assignedto']
+        for assignedto_id in assignedto_ids:
+            new_nosy.add(assignedto_id)
+
+    # see if there's any new messages - if so, possibly add the author and
+    # recipient to the nosy
+    if newvalues.has_key('messages'):
+        if nodeid is None:
+            ok = ('new', 'yes')
+            messages = newvalues['messages']
+        else:
+            ok = ('yes',)
+            # figure which of the messages now on the issue weren't
+            oldmessages = cl.get(nodeid, 'messages')
+            messages = []
+            for msgid in newvalues['messages']:
+                if msgid not in oldmessages:
+                    messages.append(msgid)
+
+        # configs for nosy modifications
+        add_author = getattr(db.config, 'ADD_AUTHOR_TO_NOSY', 'new')
+        add_recips = getattr(db.config, 'ADD_RECIPIENTS_TO_NOSY', 'new')
+
+        # now for each new message:
+        msg = db.msg
+        for msgid in messages:
+            if add_author in ok:
+                authid = msg.get(msgid, 'author')
+                new_nosy.add(authid)
+
+            # add on the recipients of the message
+            if add_recips in ok:
+                for recipient in msg.get(msgid, 'recipients'):
+                    new_nosy.add(recipient)
+
+    if current_nosy != new_nosy:
+        # that's it, save off the new nosy list
+        newvalues['nosy'] = list(new_nosy)
+
+def init(db):
+    db.bug.react('create', nosyreaction)
+    db.bug.react('set', nosyreaction)
+    db.bug.audit('create', updatenosy)
+    db.bug.audit('set', updatenosy)
+
+    db.task.react('create', nosyreaction)
+    db.task.react('set', nosyreaction)
+    db.task.audit('create', updatenosy)
+    db.task.audit('set', updatenosy)
+
+    db.milestone.react('create', nosyreaction)
+    db.milestone.react('set', nosyreaction)
+    db.milestone.audit('create', updatenosy)
+    db.milestone.audit('set', updatenosy)

share/roundup/templates/responsive/detectors/patches.py

+# Auditor for patch files
+# Patches should be declared as text/plain (also .py files),
+# independent of what the browser says, and
+# the "patch" keyword should get set automatically.
+
+import posixpath
+
+patchtypes = ('.diff', '.patch')
+sourcetypes = ('.diff', '.patch', '.py')
+
+def ispatch(file, types):
+    return posixpath.splitext(file)[1] in types
+
+def patches_text_plain(db, cl, nodeid, newvalues):
+    if ispatch(newvalues['name'], sourcetypes):
+        newvalues['type'] = 'text/plain'
+
+def patches_keyword(db, cl, nodeid, newvalues):
+    # Check whether there are any new files
+    newfiles = set(newvalues.get('files',()))
+    if nodeid:
+        newfiles -= set(db.bug.get(nodeid, 'files'))
+    # Check whether any of these is a patch
+    newpatch = False
+    for fileid in newfiles:
+        if ispatch(db.file.get(fileid, 'name'), patchtypes):
+            newpatch = True
+            break
+    if newpatch:
+        # Add the patch keyword if its not already there
+        patchid = db.keyword.lookup("patch")
+        oldkeywords = []
+        if nodeid:
+            oldkeywords = db.bug.get(nodeid, 'keywords')
+            if patchid in oldkeywords:
+                # This is already marked as a patch
+                return
+        if not newvalues.has_key('keywords'):
+            newvalues['keywords'] = oldkeywords
+        newvalues['keywords'].append(patchid)
+
+def init(db): pass
+#    db.file.audit('create', patches_text_plain)
+#    db.bug.audit('create', patches_keyword)
+#    db.bug.audit('set', patches_keyword)

share/roundup/templates/responsive/detectors/severityauditor.py

+
+def init_severity(db, cl, nodeid, newvalues):
+    """Make sure severity is set on new bugs"""
+    if newvalues.has_key('severity') and newvalues['severity']:
+        return
+