#!/usr/bin/python """ Given a CVSTrac Ticket Number, load the record from the SQLite database and send out an email. """ import sys import types import getopt import sqlite import smtplib # See #355 for an enhancement to CVSTrac that would improve this script # These are the parameters you are likely to want to change DEFAULT_DBFILE = "/var/cvstrac/trac.db" smtpServer = "mail.mydomain.com" fromAddress = "cvstrac@mydomain.com" cclist = "supervisor@mydomain.com" replyTo = "discussion@mydomain.com" subjectTemplate = "New ticket has been added for your attention: %d" ticketUrl = "http://tickets.mydomain.com/cgi-bin/cvstrac.cgi/trac/tktview?tn=%d" # This is the body of the email. If you change it, you may need to change # the parameters used on the template in the getEmailContents() function below. bodyTemplate = """ TICKET ADD/CHANGE Ticket #%d Ticket URL: %s Title: %s Status: %s Type: %s Assignee: %s (%s) Requester: %s (%s) Contact: %s Description: %s ---- Remarks ---- %s """ # This ends the user configurable section dbfile = DEFAULT_DBFILE tolist = None verbosity = 1 logfile = None pretend = False class TicketModel: """Keeps track of information about a ticket """ def __init__(self, tktnum): self.tktnum = tktnum self.type = "" self.status = "" self.origtime = "" self.changetime = "" self.derivedfrom = "" self.version = "" self.assignedto = "" self.assignemail = "" self.severity = "" self.priority = "" self.subsystem = "" self.owner = "" self.owneremail = "" self.title = "" self.contact = "" self.extra1 = "" self.extra2 = "" self.extra3 = "" self.extra4 = "" self.extra5 = "" self.description = "" self.remarks = "" def getTicketFromDatabase(tktnum, dbfile): """Takes a Ticket Number and returns a Ticket Model.""" model = TicketModel(tktnum) tktConnection = sqlite.connect(dbfile) if tktConnection is None: error("Could not connect to database") sys.exit(1) tktCursor = tktConnection.cursor() if tktCursor is None: error("Could not get Cursor from Connection") sys.exit(2) sqlstr = ( "select " + "tn, " + "type, " + "status, " + "origtime, " + "changetime, " + "derivedfrom, " + "version, " + "assignedto, " + "u.email, " + "severity, " + "priority, " + "subsystem, " + "owner, " + "o.email, " + "title, " + "contact, " + "extra1, " + "extra2, " + "extra3, " + "extra4, " + "extra5, " + "description, " + "remarks " + "from ticket t, user u, user o " + "where u.id=t.assignedto and o.id=t.owner and tn='%d'") % (tktnum) tktCursor.execute(sqlstr) row = tktCursor.fetchone() if row is None or len(row) == 0: error("Could not find Ticket #" + `tktnum` + " in database") sys.exit(3) ( model.tn, model.type, model.status, model.origtime, model.changetime, model.derivedfrom, model.version, model.assignedto, model.assignemail, model.severity, model.priority, model.subsystem, model.owner, model.owneremail, model.title, model.contact, model.extra1, model.extra2, model.extra3, model.extra4, model.extra5, model.description, model.remarks ) = row tktCursor.close() tktConnection.close() return model def getEmailContents(ticket): """This creates the body of the email as a single string""" ticketLink = ticketUrl % (ticket.tn) body = bodyTemplate % ( ticket.tn, ticketLink, ticket.title, ticket.status, ticket.type, ticket.assignedto, ticket.assignemail, ticket.owner, ticket.owneremail, ticket.contact, ticket.description, ticket.remarks) return body def sendEmail(ticket, contents, tolist, cclist): """Sends an email about a ticket add or change""" # There is only one list of to addresses if tolist is None and ticket is not None and ticket.assignemail is not None: tolist = ticket.assignemail # The CC addresses are whatever is passed in plus the ticket owner ccSet = [] if cclist is not None and ticket.owneremail is not None and ticket.owneremail not in cclist: cclist += "," + ticket.owneremail subject = subjectTemplate % (ticket.tn) msgBody = "From: %s\r\nTo: %s\r\nCc: %s\r\nSubject: %s\r\nReply-To: %s\r\n\r\n%s" % ( fromAddress, tolist, cclist, subject, replyTo, contents) recipients = (tolist + "," + cclist).split(",") if not pretend: session = smtplib.SMTP(smtpServer) session.sendmail(fromAddress, recipients, msgBody) session.quit() debug(msgBody) ### FUNCTIONS FOR RUNNING AS A COMMAND def usage(scriptname): print """%s Email a CVSTrac Ticket to users by reading a SQLite database. Usage: %s [option] ticket-number where "option" is one of: -h, --help Get this message -v, --version Print the version info -q, --quiet Quiet mode, only errors printed -d, --debug Debug mode, display debugging messages -p, --pretend Do everything except sending the email -f, --dbfile SQLite database file for CVSTrac Default is %s -t, --tolist List of email addresses to send email to -c, --cclist List of email addresses CC email to -l, --logfile Informational messages from this program """ % (getversion(), scriptname, DEFAULT_DBFILE) def getversion(): return "ticket-email V1.0" def error(str): log(str) def warn(str): if verbosity > 0: log(str) def debug(str): if verbosity > 1: log(str) def log(str): if logfile is None: print str else: logfile.write(str + "\n") def main(argv): assert argv, "Argument to ticket-email.main() left blank" assert type(argv) == types.ListType, "Wrong type passed as argument to session.main()" # Initialize main variables with default values global dbfile,tolist,cclist,verbosity,logfile,pretend SHORTOPTLIST = "hvqdpf:t:c:l:" LONGOPTLIST = "help version quiet debug pretend dbfile= tolist= cclist= logfile=".split() # Process command line parameters, replacing defaults try: optlist, remainder = getopt.getopt(argv[1:], SHORTOPTLIST, LONGOPTLIST) except getopt.GetoptError: usage(argv[0]) sys.exit(8) for opt, val in optlist: if opt in ["-h", "--help"]: usage(argv[0]) sys.exit(7) if opt in ["-v", "--version"]: print getversion() if opt in ["-q", "--quiet"]: verbosity = 0 if opt in ["-d", "--debug"]: verbosity = 2 if opt in ["-p", "--pretend"]: pretend = True if opt in ["-f", "--dbfile"]: dbfile = val if opt in ["-c", "--cclist"]: cclist = val if opt in ["-t", "--tolist"]: tolist = val if opt in ["-l", "--logfile"]: logname = val if logname is not None and len(logname) > 0: logfile = open(logname, "a") if len(remainder) < 1: print "Error: You must specify the Ticket #" usage(argv[0]) sys.exit(9) debug("Running %s with parameters %s" % (argv[0], argv)) try: tktnum = int(remainder[0]) ticket = getTicketFromDatabase(tktnum, dbfile) contents = getEmailContents(ticket) sendEmail(ticket, contents, tolist, cclist) debug("Email sent") except: errstr = str(sys.exc_info()[0]) + "\n" errstr = errstr + str(sys.exc_info()[1]) + "\n" error(errstr) if __name__ == '__main__': main(sys.argv)