classify-users: determine type of Athena accounts
[user/alex/software/my-snippets.git] / mail-merge
index f03baeac63b36e70c367cf653287ff7c0bd8460d..5de621e0098b4dc3bd46862c56d265255b92d7b6 100755 (executable)
@@ -1,12 +1,16 @@
 #!/usr/bin/python
 
-import sys
-import os
 import csv
+import email.parser
+from optparse import OptionParser
+import os
 import smtplib
 import subprocess
+import sys
+
 
 sender_header = 'mail-merge-sender@mit.edu'
+rtkit_path = '/afs/athena.mit.edu/user/a/d/adehnert/arch/common/lib/python/'
 smtp = None
 
 def dictize_line(header, line,):
@@ -29,22 +33,107 @@ def sendmail_cmd(addrs, text):
     args.extend(addrs)
     proc = subprocess.Popen(args, stdin=subprocess.PIPE)
     proc.communicate(text)
+    if proc.returncode != 0:
+        raise RuntimeError, "sendmail returned %d" % (proc.returncode, )
 cmd_funcs = (lambda: True, sendmail_cmd)
 
 setup_sendmail, sendmail = smtp_funcs
 setup_sendmail, sendmail = cmd_funcs
 
-if __name__=='__main__':
-    print "Syntax: $script $cc_addr $template $recipients"
-    setup_sendmail()
-    cc_addr = sys.argv[1]
-    email_file = sys.argv[2]
-    email = open(email_file, 'r').read()
-    reader = csv.reader(open(sys.argv[3]))
+def parse_arguments():
+    parser = OptionParser(usage='usage: %prog [options] cc_addr template recipients')
+    parser.add_option('-q', '--rt-queue', dest='rt_queue',
+            help='Automatically create a ticket in queue QUEUE',
+            metavar='QUEUE',
+    )
+    parser.add_option('-o', '--rt-owner', dest='rt_owner',
+            help='Set RT owner and AdminCC to USER',
+            metavar='USER',
+    )
+    parser.add_option('--split', dest='split',
+            help='Split "email" field on SPLIT and send to each recipient',
+            metavar='SPLIT',
+    )
+    (options, args) = parser.parse_args()
+    if len(args) != 3:
+        parser.error("incorrect number of arguments")
+    if options.rt_owner and not options.rt_queue:
+        parser.error("--rt-owner requires specifying a queue")
+    return options, args
+
+def nop_msg_filter(rcpts, body):
+    return rcpts, body
+
+def msg_filter_factory(opts):
+    if not opts.rt_queue:
+        return nop_msg_filter
+
+    try:
+        import rtkit.tracker, rtkit.authenticators, rtkit.errors
+    except ImportError:
+        print "Note: using rtkit from %s" % (rtkit_path, )
+        sys.path.append(rtkit_path)
+        import rtkit.tracker, rtkit.authenticators, rtkit.errors
+
+    cookie = rtkit.authenticators.CookieAuthenticator
+    resource = rtkit.resource.RTResource.from_rtrc(cookie)
+    parser = email.parser.Parser()
+
+    def filter_rt(rcpts, body, ):
+        msg = parser.parsestr(body)
+        content = {
+            'content': {
+                'Requestors': ", ".join(rcpts),
+                'Queue': opts.rt_queue,
+                'Subject' : msg['Subject'],
+                'Text' : '',
+            }
+        }
+        if opts.rt_owner:
+            content['content']['AdminCC'] = opts.rt_owner
+            content['content']['Owner'] = opts.rt_owner
+
+        try:
+            response = resource.post(path='ticket/new', payload=content,)
+            results = dict(response.parsed[0])
+            ticket, ticket_number = results['id'].split('/')
+            assert ticket == 'ticket', 'unexpected value "%s" instead of ticket' % (ticket, )
+            subject = "%s [help.mit.edu #%s]" % (msg['Subject'], ticket_number)
+            del msg['Subject']
+            msg['Subject'] = subject
+        except rtkit.errors.RTResourceError as e:
+            logger.error(e.response.status_int)
+            logger.error(e.response.status)
+            logger.error(e.response.parsed)
+
+        # We don't want to send mail to the real recipient, because RT
+        # will send them a copy too.
+        return [], msg.as_string()
+
+    return filter_rt
+
+def mail_merge(opts, cc_addr, email_file, recipients_file):
+    email_tmpl = open(email_file, 'rU').read()
+    reader = csv.reader(open(recipients_file, 'rU'))
     header = reader.next()
+    msg_filter = msg_filter_factory(opts)
     print header
+    if not 'email' in header:
+        print >>sys.stderr, "Your CSV file doesn't have an email field. You should fix that.\n(Note that this script is case-sensitive.)"
+        return False
     for line in reader:
         dct = dictize_line(header, line, )
         print dct
-        text = email % dct
-        sendmail([dct['email'], cc_addr, ], text, )
+        text = email_tmpl % dct
+        if opts.split:
+            prop_rcpts = dct['email'].split(opts.split)
+        else:
+            prop_rcpts = [dct['email']]
+        rcpts, text = msg_filter(prop_rcpts, text, )
+        rcpts.append(cc_addr)
+        sendmail(rcpts, text, )
+
+if __name__=='__main__':
+    options, args = parse_arguments()
+    setup_sendmail()
+    mail_merge(options, *args)