Code

add and use Reject exception (sf bug 700265)
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 26 Mar 2004 00:44:11 +0000 (00:44 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Fri, 26 Mar 2004 00:44:11 +0000 (00:44 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@2197 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
doc/customizing.txt
roundup/cgi/actions.py
roundup/cgi/exceptions.py
roundup/exceptions.py [new file with mode: 0644]
roundup/mailgw.py

index ea8067070ce8f06d29696aafa34d03cca130c1d7..b00dbb9c70dd08e556c0913377aee4acd9922a90 100644 (file)
@@ -7,12 +7,16 @@ Feature:
 - added new auditor, emailauditor.py, that works around a bug in IE. See 
   emailauditor.py for more info.
 - added dispatcher functionality - see upgrading.txt for more info
+- added Reject exception which may be raised by auditors. This is trapped
+  by mailgw and may be used to veto creation of file attachments or
+  messages. (sf bug 700265)
 
 Fixed:
 - Boolean HTML templating was broken
 - Link HTML templating field() was broken
 - Fix reporting of test inclusion in postgresql test
 
+
 2004-03-24 0.7.0b1
 Major new features:
 - added postgresql backend (originally from sf patch 761740, many changes
index 27e73bbf12c7d8db46184e0480ad85a9dc30d84c..084d334836944ca5f71ef6c666508b142d368861 100644 (file)
@@ -2,7 +2,7 @@
 Customising Roundup
 ===================
 
-:Version: $Revision: 1.122 $
+:Version: $Revision: 1.123 $
 
 .. This document borrows from the ZopeBook section on ZPT. The original is at:
    http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
@@ -586,6 +586,37 @@ to use one, copy it to the ``'detectors'`` of your tracker instance:
         db.issue.react('create', newissuecopy)
 
 
+Auditor or Reactor?
+-------------------
+
+Generally speaking, the following rules should be observed:
+
+**Auditors**
+  Are used for `vetoing creation of or changes to items`_. They might
+  also make automatic changes to item properties.
+**Reactors**
+  Detect changes in the database and react accordingly. They should avoid
+  making changes to the database where possible, as this could create
+  detector loops.
+
+Vetoing creation of or changes to items
+---------------------------------------
+
+Auditors may raise the ``Reject`` exception to prevent the creation of
+or changes to items in the database.  The mail gateway, for example, will
+not attach files or messages to issues when the creation of those files or
+messages are prevented through the ``Reject`` exception. It'll also not create
+users if that creation is ``Reject``'ed too.
+
+To use, simply add at the top of your auditor::
+
+   from roundup.exceptions import Reject
+
+And then when your rejection criteria have been detected, simply::
+
+   raise Reject
+
+
 Database Content
 ================
 
index 5fbbf228ef1b569ca3f8896e152a248677a02a48..42bd7ecde4ce111890b57bf924e738f3cbe89857 100755 (executable)
@@ -1,3 +1,5 @@
+#$Id: actions.py,v 1.15 2004-03-26 00:44:11 richard Exp $
+
 import re, cgi, StringIO, urllib, Cookie, time, random
 
 from roundup import hyperdb, token, date, password, rcsv
@@ -837,3 +839,4 @@ class ExportCSVAction(Action):
 
         return '\n'
 
+# vim: set filetype=python ts=4 sw=4 et si
index 29298952c7096fb7d75477eb5099a3227877959c..1d24fc1b3c56d631c290c5977c4fb4d343b08124 100755 (executable)
@@ -1,3 +1,9 @@
+#$Id: exceptions.py,v 1.4 2004-03-26 00:44:11 richard Exp $
+'''Exceptions for use in Roundup's web interface.
+'''
+
+__docformat__ = 'restructuredtext'
+
 import cgi
 
 class HTTPException(Exception):
@@ -51,3 +57,4 @@ class SeriousError(Exception):
 </body></html>
 '''%cgi.escape(self.args[0])
 
+# vim: set filetype=python ts=4 sw=4 et si
diff --git a/roundup/exceptions.py b/roundup/exceptions.py
new file mode 100644 (file)
index 0000000..27cc1ef
--- /dev/null
@@ -0,0 +1,19 @@
+#$Id: exceptions.py,v 1.1 2004-03-26 00:44:11 richard Exp $
+'''Exceptions for use across all Roundup components.
+'''
+
+__docformat__ = 'restructuredtext'
+
+class Reject(Exception):
+    '''An auditor may raise this exception when the current create or set
+    operation should be stopped.
+
+    It is up to the specific interface invoking the create or set to
+    handle this exception sanely. For example:
+
+    - mailgw will trap and ignore Reject for file attachments and messages
+    - cgi will trap and present the exception in a nice format
+    '''
+    pass
+
+# vim: set filetype=python ts=4 sw=4 et si
index d6768758397eb4c364676831387b613c5f43284e..47d0831099bff7579ab1f7e7fd3311c29b4d5999 100644 (file)
@@ -72,7 +72,7 @@ are calling the create() method to create a new node). If an auditor raises
 an exception, the original message is bounced back to the sender with the
 explanatory message given in the exception. 
 
-$Id: mailgw.py,v 1.145 2004-03-25 22:52:12 richard Exp $
+$Id: mailgw.py,v 1.146 2004-03-26 00:44:11 richard Exp $
 """
 __docformat__ = 'restructuredtext'
 
@@ -80,7 +80,7 @@ import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri
 import time, random, sys
 import traceback, MimeWriter, rfc822
 
-from roundup import hyperdb, date, password, rfc2822
+from roundup import hyperdb, date, password, rfc2822, exceptions
 from roundup.mailer import Mailer
 
 SENDMAILDEBUG = os.environ.get('SENDMAILDEBUG', '')
@@ -805,8 +805,13 @@ not find a text/plain part to use.
             for (name, mime_type, data) in attachments:
                 if not name:
                     name = "unnamed"
-                files.append(self.db.file.create(type=mime_type, name=name,
-                                                 content=data, **file_props))
+                try:
+                    fileid = self.db.file.create(type=mime_type, name=name,
+                         content=data, **file_props)
+                except exceptions.Reject:
+                    pass
+                else:
+                    files.append(fileid)
             # attach the files to the issue
             if nodeid:
                 # extend the existing files list
@@ -821,20 +826,23 @@ not find a text/plain part to use.
         # create the message if there's a message body (content)
         #
         if (content and properties.has_key('messages')):
-            message_id = self.db.msg.create(author=author,
-                recipients=recipients, date=date.Date('.'), summary=summary,
-                content=content, files=files, messageid=messageid,
-                inreplyto=inreplyto, **msg_props)
-
-            # attach the message to the node
-            if nodeid:
-                # add the message to the node's list
-                messages = cl.get(nodeid, 'messages')
-                messages.append(message_id)
-                props['messages'] = messages
+            try:
+                message_id = self.db.msg.create(author=author,
+                    recipients=recipients, date=date.Date('.'),
+                    summary=summary, content=content, files=files,
+                    messageid=messageid, inreplyto=inreplyto, **msg_props)
+            except exceptions.Reject:
+                pass
             else:
-                # pre-load the messages list
-                props['messages'] = [message_id]
+                # attach the message to the node
+                if nodeid:
+                    # add the message to the node's list
+                    messages = cl.get(nodeid, 'messages')
+                    messages.append(message_id)
+                    props['messages'] = messages
+                else:
+                    # pre-load the messages list
+                    props['messages'] = [message_id]
 
         #
         # perform the node change / create
@@ -948,10 +956,13 @@ def uidFromAddress(db, address, create=1, **user_props):
             trying = username + str(n)
 
         # create!
-        return db.user.create(username=trying, address=address,
-            realname=realname, roles=db.config.NEW_EMAIL_USER_ROLES,
-            password=password.Password(password.generatePassword()),
-            **user_props)
+        try:
+            return db.user.create(username=trying, address=address,
+                realname=realname, roles=db.config.NEW_EMAIL_USER_ROLES,
+                password=password.Password(password.generatePassword()),
+                **user_props)
+        except exceptions.Reject:
+            return 0
     else:
         return 0