Code

Fixed issues with nosy reaction and author copies.
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Mon, 12 Nov 2001 22:01:07 +0000 (22:01 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Mon, 12 Nov 2001 22:01:07 +0000 (22:01 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@391 57a73879-2fb5-44c3-a270-3262357dd7e2

roundup-admin
roundup/hyperdb.py
roundup/instance.py
roundup/mailgw.py
roundup/roundupdb.py
roundup/templates/classic/detectors/nosyreaction.py
roundup/templates/extended/detectors/nosyreaction.py

index a7f2be7195d1fba7c1271e3d7dc66f2cd08c2f63..4065e33d7d8682f6b946605ff35a9e22b2f5bcdd 100755 (executable)
@@ -16,7 +16,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: roundup-admin,v 1.43 2001-11-09 22:33:28 richard Exp $
+# $Id: roundup-admin,v 1.44 2001-11-12 22:01:06 richard Exp $
 
 import sys
 if int(sys.version[0]) < 2:
@@ -64,6 +64,7 @@ class AdminTool:
         for k in AdminTool.__dict__.keys():
             if k[:5] == 'help_':
                 self.help[k[5:]] = getattr(self, k)
+        self.db = None
 
     def usage(message=''):
         if message: message = 'Problem: '+message+'\n'
@@ -799,11 +800,15 @@ Command help:
             self.instance_home = raw_input('Enter instance home: ').strip()
 
         # before we open the db, we may be doing an init
-        if command == 'init':
-            return self.do_init(self.instance_home, args)
+        if command == 'initialise':
+            return self.do_initialise(self.instance_home, args)
 
         # get the instance
-        instance = roundup.instance.open(self.instance_home)
+        try:
+            instance = roundup.instance.open(self.instance_home)
+        except ValueError, message:
+            print "Couldn't open instance: %s"%message
+            return 1
         self.db = instance.open('admin')
 
         if len(args) < 2:
@@ -872,7 +877,8 @@ Command help:
             self.interactive()
         else:
             ret = self.run_command(args)
-        self.db.close()
+        if self.db:
+            self.db.close()
         return ret
 
 
@@ -882,6 +888,9 @@ if __name__ == '__main__':
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.43  2001/11/09 22:33:28  richard
+# More error handling fixes.
+#
 # Revision 1.42  2001/11/09 10:11:08  richard
 #  . roundup-admin now handles all hyperdb exceptions
 #
index 49a6db60af35032e02da001eaaac64daa5cee031..5a4e837645f4e11bffea554a3f3de7ede402fd4e 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: hyperdb.py,v 1.30 2001-11-09 10:11:08 richard Exp $
+# $Id: hyperdb.py,v 1.31 2001-11-12 22:01:06 richard Exp $
 
 # standard python modules
 import cPickle, re, string
@@ -545,7 +545,7 @@ class Class:
             if node.has_key(self.db.RETIRED_FLAG):
                 continue
             for key, value in requirements.items():
-                if node[key].lower() != value:
+                if node[key] and node[key].lower() != value:
                     break
             else:
                 l.append(nodeid)
@@ -849,6 +849,9 @@ def Choice(name, *options):
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.30  2001/11/09 10:11:08  richard
+#  . roundup-admin now handles all hyperdb exceptions
+#
 # Revision 1.29  2001/10/27 00:17:41  richard
 # Made Class.stringFind() do caseless matching.
 #
index 77dbb26dcf6013cb5826b8911f3e6c2e6ab51b6a..59c56fb50522909ace0cad904b53d9985ff73d1f 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: instance.py,v 1.3 2001-08-07 00:24:42 richard Exp $
+# $Id: instance.py,v 1.4 2001-11-12 22:01:06 richard Exp $
 
 ''' Currently this module provides one function: open. This function opens
 an instance.
 '''
 
-import imp
+import imp, os
 
 class Opener:
     def __init__(self):
@@ -29,6 +29,12 @@ class Opener:
         self.instances = {}
 
     def open(self, instance_home):
+        '''Open the instance.
+
+        Raise ValueError if the instance home doesn't exist.
+        '''
+        if not os.path.exists(instance_home):
+            raise ValueError, 'no such directory: "%s"'%instance_home
         if self.instances.has_key(instance_home):
             return imp.load_package(self.instances[instance_home],
                 instance_home)
@@ -46,6 +52,9 @@ del opener
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.3  2001/08/07 00:24:42  richard
+# stupid typo
+#
 # Revision 1.2  2001/08/07 00:15:51  richard
 # Added the copyright/license notice to (nearly) all files at request of
 # Bizar Software.
index de3e1e1bec92b185c090a791a0bd0ac87e151b32..17f62f7e42287d2c1cf94afa72977029be1f9847 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.30 2001-11-09 22:33:28 richard Exp $
+$Id: mailgw.py,v 1.31 2001-11-12 22:01:06 richard Exp $
 '''
 
 
@@ -138,7 +138,8 @@ class MailGW:
         if sendto:
             try:
                 self.handle_message(message)
-                return
+                sendto = [sendto[0][1]]
+                m = ['Subject: Well, it seemed to work', '', 'hi, mum!']
             except MailUsageError, value:
                 # bounce the message back to the sender with the usage message
                 fulldoc = '\n'.join(string.split(__doc__, '\n')[2:])
@@ -150,8 +151,7 @@ class MailGW:
             except:
                 # bounce the message back to the sender with the error message
                 sendto = [sendto[0][1]]
-                m = ['Subject: failed issue tracker submission']
-                m.append('')
+                m = ['Subject: failed issue tracker submission', '']
                 # TODO as attachments?
                 m.append('----  traceback of failure  ----')
                 s = cStringIO.StringIO()
@@ -516,6 +516,9 @@ def parseContent(content, blank_line=re.compile(r'[\r\n]+\s*[\r\n]+'),
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.30  2001/11/09 22:33:28  richard
+# More error handling fixes.
+#
 # Revision 1.29  2001/11/07 05:29:26  richard
 # Modified roundup-mailgw so it can read e-mails from a local mail spool
 # file. Truncates the spool file after parsing.
index ab3e0f3de796c6aad5fc835f08c3656dff94e672..d0ef649bf6152e11e8c6e01d857ea9fc9e4c9c91 100644 (file)
@@ -15,7 +15,7 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: roundupdb.py,v 1.16 2001-10-30 00:54:45 richard Exp $
+# $Id: roundupdb.py,v 1.17 2001-11-12 22:01:06 richard Exp $
 
 import re, os, smtplib, socket
 
@@ -31,6 +31,7 @@ def splitDesignator(designator, dre=re.compile(r'([^\d]+)(\d+)')):
         raise DesignatorError, '"%s" not a node designator'%designator
     return m.group(1), m.group(2)
 
+
 class Database:
     def getuid(self):
         """Return the id of the "user" node associated with the user
@@ -214,6 +215,12 @@ class FileClass(Class):
             d['content'] = hyperdb.String()
         return d
 
+class MessageSendError(RuntimeError):
+    pass
+
+class DetectorError(RuntimeError):
+    pass
+
 # XXX deviation from spec - was called ItemClass
 class IssueClass(Class):
     # configuration
@@ -266,17 +273,18 @@ class IssueClass(Class):
         r = {}
         for recipid in recipients:
             r[recipid] = 1
+        rlen = len(recipients)
 
         # figure the author's id, and indicate they've received the message
         authid = self.db.msg.get(msgid, 'author')
-        r[authid] = 1
 
-        sendto = []
         # ... but duplicate the message to the author as long as it's not
         # the anonymous user
         if (self.MESSAGES_TO_AUTHOR == 'yes' and
                 self.db.user.get(authid, 'username') != 'anonymous'):
-            sendto.append(authid)
+            if not r.has_key(authid):
+                recipients.append(authid)
+        r[authid] = 1
 
         # now figure the nosy people who weren't recipients
         nosy = self.get(nodeid, 'nosy')
@@ -286,46 +294,50 @@ class IssueClass(Class):
             # do...)
             if self.db.user.get(nosyid, 'username') == 'anonymous': continue
             if not r.has_key(nosyid):
-                sendto.append(nosyid)
                 recipients.append(nosyid)
 
-        if sendto:
-            # update the message's recipients list
-            self.db.msg.set(msgid, recipients=recipients)
-
-            # send an email to the people who missed out
-            sendto = [self.db.user.get(i, 'address') for i in recipients]
-            cn = self.classname
-            title = self.get(nodeid, 'title') or '%s message copy'%cn
-            # figure author information
-            authname = self.db.user.get(authid, 'realname')
-            if not authname:
-                authname = self.db.user.get(authid, 'username')
-            authaddr = self.db.user.get(authid, 'address')
-            if authaddr:
-                authaddr = '<%s> '%authaddr
-            else:
-                authaddr = ''
-            # TODO attachments
-            m = ['Subject: [%s%s] %s'%(cn, nodeid, title)]
-            m.append('To: %s'%', '.join(sendto))
-            m.append('From: %s'%self.ISSUE_TRACKER_EMAIL)
-            m.append('Reply-To: %s'%self.ISSUE_TRACKER_EMAIL)
-            m.append('')
-            # add author information
-            m.append("%s %sadded the comment:"%(authname, authaddr))
-            m.append('')
-            # add the content
-            m.append(self.db.msg.get(msgid, 'content'))
-            # "list information" footer
-            m.append(self.email_footer(nodeid, msgid))
-            try:
-                smtp = smtplib.SMTP(self.MAILHOST)
-                smtp.sendmail(self.ISSUE_TRACKER_EMAIL, sendto, '\n'.join(m))
-            except socket.error, value:
-                return "Couldn't send confirmation email: mailhost %s"%value
-            except smtplib.SMTPException, value:
-                return "Couldn't send confirmation email: %s"%value
+        # no new recipients
+        if rlen == len(recipients):
+            return
+
+        # update the message's recipients list
+        self.db.msg.set(msgid, recipients=recipients)
+
+        # send an email to the people who missed out
+        sendto = [self.db.user.get(i, 'address') for i in recipients]
+        cn = self.classname
+        title = self.get(nodeid, 'title') or '%s message copy'%cn
+        # figure author information
+        authname = self.db.user.get(authid, 'realname')
+        if not authname:
+            authname = self.db.user.get(authid, 'username')
+        authaddr = self.db.user.get(authid, 'address')
+        if authaddr:
+            authaddr = '<%s> '%authaddr
+        else:
+            authaddr = ''
+        # TODO attachments
+        m = ['Subject: [%s%s] %s'%(cn, nodeid, title)]
+        m.append('To: %s'%', '.join(sendto))
+        m.append('From: %s'%self.ISSUE_TRACKER_EMAIL)
+        m.append('Reply-To: %s'%self.ISSUE_TRACKER_EMAIL)
+        m.append('')
+        # add author information
+        m.append("%s %sadded the comment:"%(authname, authaddr))
+        m.append('')
+        # add the content
+        m.append(self.db.msg.get(msgid, 'content'))
+        # "list information" footer
+        m.append(self.email_footer(nodeid, msgid))
+        try:
+            smtp = smtplib.SMTP(self.MAILHOST)
+            smtp.sendmail(self.ISSUE_TRACKER_EMAIL, sendto, '\n'.join(m))
+        except socket.error, value:
+            raise MessageSendError, \
+                "Couldn't send confirmation email: mailhost %s"%value
+        except smtplib.SMTPException, value:
+            raise MessageSendError, \
+                 "Couldn't send confirmation email: %s"%value
 
     def email_footer(self, nodeid, msgid):
         ''' Add a footer to the e-mail with some useful information
@@ -339,6 +351,12 @@ Roundup issue tracker
 
 #
 # $Log: not supported by cvs2svn $
+# Revision 1.16  2001/10/30 00:54:45  richard
+# Features:
+#  . #467129 ] Lossage when username=e-mail-address
+#  . #473123 ] Change message generation for author
+#  . MailGW now moves 'resolved' to 'chatting' on receiving e-mail for an issue.
+#
 # Revision 1.15  2001/10/23 01:00:18  richard
 # Re-enabled login and registration access after lopping them off via
 # disabling access for anonymous users.
index df0651ed2b94864225dff4d8c5a0d5447727539e..876219784d4545e17d4bcc6c10178ed5d763223e 100644 (file)
@@ -15,7 +15,9 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: nosyreaction.py,v 1.4 2001-10-30 00:54:45 richard Exp $
+#$Id: nosyreaction.py,v 1.5 2001-11-12 22:01:07 richard Exp $
+
+from roundup import roundupdb
 
 def nosyreaction(db, cl, nodeid, oldvalues):
     ''' A standard detector is provided that watches for additions to the
@@ -51,7 +53,10 @@ def nosyreaction(db, cl, nodeid, oldvalues):
 
     # send a copy to the nosy list
     for msgid in messages:
-        cl.sendmessage(nodeid, msgid)
+        try:
+            cl.sendmessage(nodeid, msgid)
+        except roundupdb.MessageSendError, message:
+            raise roundupdb.DetectorError, message
 
     # update the nosy list with the recipients from the new messages
     nosy = cl.get(nodeid, 'nosy')
@@ -82,6 +87,12 @@ def init(db):
 
 #
 #$Log: not supported by cvs2svn $
+#Revision 1.4  2001/10/30 00:54:45  richard
+#Features:
+# . #467129 ] Lossage when username=e-mail-address
+# . #473123 ] Change message generation for author
+# . MailGW now moves 'resolved' to 'chatting' on receiving e-mail for an issue.
+#
 #Revision 1.3  2001/08/07 00:24:43  richard
 #stupid typo
 #
index 45e6cee4644972bb55394c196b1325046bd1ab37..ea8f69576c7187347c3b8f302034e5f834ee2f2f 100644 (file)
@@ -15,7 +15,9 @@
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-#$Id: nosyreaction.py,v 1.4 2001-10-30 00:54:45 richard Exp $
+#$Id: nosyreaction.py,v 1.5 2001-11-12 22:01:07 richard Exp $
+
+from roundup import roundupdb
 
 def nosyreaction(db, cl, nodeid, oldvalues):
     ''' A standard detector is provided that watches for additions to the
@@ -51,7 +53,10 @@ def nosyreaction(db, cl, nodeid, oldvalues):
 
     # send a copy to the nosy list
     for msgid in messages:
-        cl.sendmessage(nodeid, msgid)
+        try:
+            cl.sendmessage(nodeid, msgid)
+        except roundupdb.MessageSendError, message:
+            raise roundupdb.DetectorError, message
 
     # update the nosy list with the recipients from the new messages
     nosy = cl.get(nodeid, 'nosy')
@@ -82,6 +87,12 @@ def init(db):
 
 #
 #$Log: not supported by cvs2svn $
+#Revision 1.4  2001/10/30 00:54:45  richard
+#Features:
+# . #467129 ] Lossage when username=e-mail-address
+# . #473123 ] Change message generation for author
+# . MailGW now moves 'resolved' to 'chatting' on receiving e-mail for an issue.
+#
 #Revision 1.3  2001/08/07 00:24:43  richard
 #stupid typo
 #