def _validate_mimebody(self, mime, ticket, newtk): """Body of a ticket notification message""" (mime_decoder, mime_name, mime_charset) = mime tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=newtk) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) self.failIf('MIME-Version' not in headers) self.failIf('Content-Type' not in headers) self.failIf('Content-Transfer-Encoding' not in headers) self.failIf(not re.compile(r"1.\d").match(headers['MIME-Version'])) type_re = re.compile(r'^text/plain;\scharset="([\w\-\d]+)"$') charset = type_re.match(headers['Content-Type']) self.failIf(not charset) charset = charset.group(1) self.assertEqual(charset, mime_charset) self.assertEqual(headers['Content-Transfer-Encoding'], mime_name) # checks the width of each body line for line in body.splitlines(): self.failIf(len(line) > MAXBODYWIDTH) # attempts to decode the body, following the specified MIME endoding # and charset try: if mime_decoder: body = mime_decoder.decodestring(body) body = unicode(body, charset) except Exception, e: raise AssertionError, e
def _test_updater(disable): if disable: self.env.config.set('notification','always_notify_updater', 'false') ticket = Ticket(self.env) ticket['reporter'] = '*****@*****.**' ticket['summary'] = u'This is a súmmäry' ticket['cc'] = '*****@*****.**' ticket.insert() ticket['component'] = 'dummy' now = time.time() ticket.save_changes('*****@*****.**', 'This is a change', when=now) tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=now) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # checks for header existence self.failIf(not headers) # checks for updater in the 'To' recipient list self.failIf('To' not in headers) tolist = [addr.strip() for addr in headers['To'].split(',')] if disable: self.failIf('*****@*****.**' in tolist) else: self.failIf('*****@*****.**' not in tolist)
def test_recipients(self): """To/Cc recipients""" ticket = Ticket(self.env) ticket['reporter'] = '"Joe User" <*****@*****.**>' ticket['owner'] = '*****@*****.**' ticket['cc'] = '[email protected], [email protected], ' \ '*****@*****.**' ticket['summary'] = 'Foo' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) recipients = notifysuite.smtpd.get_recipients() # checks there is no duplicate in the recipient list rcpts = [] for r in recipients: self.failIf(r in rcpts) rcpts.append(r) # checks that all cc recipients have been notified cc_list = self.env.config.get('notification', 'smtp_always_cc') cc_list = "%s, %s" % (cc_list, ticket['cc']) for r in cc_list.replace(',', ' ').split(): self.failIf(r not in recipients) # checks that owner has been notified self.failIf(smtp_address(ticket['owner']) not in recipients) # checks that reporter has been notified self.failIf(smtp_address(ticket['reporter']) not in recipients)
def save_ticket(self, tckt, msg): # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(tckt, None): if change['permanent']: cnum += 1 nowdt = self.now nowdt = to_datetime(nowdt) tckt.save_changes(self.authname, msg, nowdt, cnum=str(cnum + 1)) ## Often the time overlaps and causes a db error, ## especially when the trac integration post-commit hook is used. ## NOTE TO SELF. I DON'T THINK THIS IS NECESSARY RIGHT NOW... #count = 0 #while count < 10: # try: # tckt.save_changes(self.authname, msg, self.now, cnum=cnum+1) # count = 42 # except Exception, e: # self.now += 1 # count += 1 tn = TicketNotifyEmail(self.env) tn.notify(tckt, newticket=0, modtime=nowdt) # We fudge time as it has to be unique self.now += 1
def handle_commit(commit, env): from trac.ticket.notification import TicketNotifyEmail from trac.ticket import Ticket from trac.util.text import to_unicode from trac.util.datefmt import utc msg = to_unicode(call_git('rev-list', ['-n', '1', commit, '--pretty=medium']).rstrip()) eml = to_unicode(call_git('rev-list', ['-n', '1', commit, '--pretty=format:%ae']).splitlines()[1]) now = datetime.now(utc) tickets = {} for cmd, tkts in command_re.findall(msg.split('\n\n', 1)[1]): action = COMMANDS.get(cmd.lower()) if action: for tkt_id in ticket_re.findall(tkts): tickets.setdefault(tkt_id, []).append(action) for tkt_id, actions in tickets.iteritems(): try: db = env.get_db_cnx() ticket = Ticket(env, int(tkt_id), db) if 'close' in actions: ticket['status'] = 'closed' ticket['resolution'] = 'fixed' # trac 1.0: `db` parameter is no longer needed and will be removed in 1.1.1 # trac 1.0: `cnum` parameter is deprecated ticket.save_changes(eml, msg, now) db.commit() tn = TicketNotifyEmail(env) tn.notify(ticket, newticket=0, modtime=now) except Exception, e: print >>sys.stderr, 'Unexpected error while processing ticket ID %s: %s' % (tkt_id, e)
def create(self, req, summary, description, attributes = {}, notify=False): """ Create a new ticket, returning the ticket ID. PS: Borrowed from XmlRpcPlugin. """ t = Ticket(self.env) t['summary'] = summary t['description'] = description t['reporter'] = req.authname for k, v in attributes.iteritems(): t[k] = v t['status'] = 'new' t['resolution'] = '' t.insert() # Call ticket change listeners ts = TicketSystem(self.env) for listener in ts.change_listeners: listener.ticket_created(t) if notify: try: tn = TicketNotifyEmail(self.env) tn.notify(t, newticket=True) except Exception, e: self.log.exception("Failure sending notification on creation " "of ticket #%s: %s" % (t.id, e))
def apply_action_side_effects(self, req, ticket, action): """Add a cross-reference comment to the other ticket""" # TODO: This needs a lot more error checking. id = 'action_%s_xref' % action ticketnum = req.args.get(id).strip('#') actions = self.get_configurable_workflow().actions author = req.authname # Add a comment to the "remote" ticket to indicate this ticket is # related to it. format_string = actions[action].get( 'xref', 'Ticket %s is related to this ticket') comment = format_string % ('#%s' % ticket.id) # FIXME: we need a cnum to avoid messing up xticket = model.Ticket(self.env, ticketnum) # FIXME: We _assume_ we have sufficient permissions to comment on the # other ticket. now = datetime.now(utc) xticket.save_changes(author, comment, now) #Send notification on the other ticket try: tn = TicketNotifyEmail(self.env) tn.notify(xticket, newticket=False, modtime=now) except Exception, e: self.log.exception("Failure sending notification on change to " "ticket #%s: %s" % (ticketnum, e))
def _test_default_domain(enabled): self.env.config.set('notification', 'always_notify_owner', 'false') self.env.config.set('notification', 'always_notify_reporter', 'false') self.env.config.set('notification', 'smtp_always_cc', '') ticket = Ticket(self.env) ticket['cc'] = 'joenodom, [email protected]' ticket['summary'] = 'This is a summary' ticket.insert() # Be sure that at least one email address is valid, so that we # send a notification even if other addresses are not valid self.env.config.set('notification', 'smtp_always_cc', '*****@*****.**') if enabled: self.env.config.set('notification', 'smtp_default_domain', 'example.org') tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should always have a 'Cc' field self.failIf('Cc' not in headers) cclist = [addr.strip() for addr in headers['Cc'].split(',')] self.failIf('*****@*****.**' not in cclist) self.failIf('*****@*****.**' not in cclist) if not enabled: self.failIf(len(cclist) != 2) self.failIf('joenodom' in cclist) else: self.failIf(len(cclist) != 3) self.failIf('*****@*****.**' not in cclist)
def test_ignore_domains(self): """Non-SMTP domain exclusion""" self.env.config.set('notification', 'ignore_domains', 'example.com, example.org') self.env.known_users = \ [('*****@*****.**', 'No Email', ''), ('*****@*****.**', 'With Email', '*****@*****.**')] ticket = Ticket(self.env) ticket['reporter'] = '*****@*****.**' ticket['owner'] = '*****@*****.**' ticket['summary'] = 'This is a summary' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should always have a 'To' field self.failIf('To' not in headers) tolist = [addr.strip() for addr in headers['To'].split(',')] # 'To' list should not contain addresses with non-SMTP domains self.failIf('*****@*****.**' in tolist) self.failIf('*****@*****.**' in tolist) # 'To' list should have been resolved to the actual email address self.failIf('*****@*****.**' not in tolist) self.failIf(len(tolist) != 1)
def execute(self): """Execute the parsed commands""" #print "Commands: %s" % self.commands # Now parse the command in the ticket, and react accordingly # Cannnot produce error messages, as the pre-commit-hook would have failed already parser = CommitMessageCommandParser(self.env, self.changeset.message) parsed_commands = parser.validate_and_parse_commit_message() self.commands = dict() for command, ticket_id, remaining_time in parsed_commands: # REFACT: the parser should give the ids as ints already ticket_id = int(ticket_id) self.commands.setdefault(ticket_id, list()) self.commands.get(ticket_id).append( self.findCommand(command, remaining=remaining_time[:-1])) # Sort the ticket in reverse order by id, it will be most likely # that a task is existing after a User Story has been created, # in which case it will be possible to execute multiple command in # a hierarchy. TODO: Check hierarchy, but very expensive keys = self.commands.keys() keys.sort(reverse=True) for t_id, cmds in [(key, self.commands[key]) for key in keys]: ticket = self.tm.get(tkt_id=t_id) for cmd in cmds: cmd(ticket) self.tm.save(ticket, author=self.author, comment=self.message) from trac.ticket.notification import TicketNotifyEmail tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=ticket.time_changed) # We need to invalidate the chart cache here because some tickets may # have been closed through commit comments. Unfortunately there is # no way to access the shared memory right now, see #565 return True
def apply_action_side_effects(self, req, ticket, action): """Add a cross-reference comment to the other ticket""" # TODO: This needs a lot more error checking. id = 'action_%s_xref' % action ticketnum = req.args.get(id).strip('#') actions = self.get_configurable_workflow().actions author = req.authname # Add a comment to the "remote" ticket to indicate this ticket is # related to it. format_string = actions[action].get('xref', 'Ticket %s is related to this ticket') comment = format_string % ('#%s' % ticket.id) # FIXME: we need a cnum to avoid messing up xticket = model.Ticket(self.env, ticketnum) # FIXME: We _assume_ we have sufficient permissions to comment on the # other ticket. now = datetime.now(utc) xticket.save_changes(author, comment, now) #Send notification on the other ticket try: tn = TicketNotifyEmail(self.env) tn.notify(xticket, newticket=False, modtime=now) except Exception, e: self.log.exception("Failure sending notification on change to " "ticket #%s: %s" % (ticketnum, e))
def test_date(self): """Date format compliance (RFC822) we do not support 'military' format""" date_str = r"^((?P<day>\w{3}),\s*)*(?P<dm>\d{2})\s+" \ r"(?P<month>\w{3})\s+(?P<year>200\d)\s+" \ r"(?P<hour>\d{2}):(?P<min>[0-5][0-9])" \ r"(:(?P<sec>[0-5][0-9]))*\s" \ r"((?P<tz>\w{2,3})|(?P<offset>[+\-]\d{4}))$" date_re = re.compile(date_str) # python time module does not detect incorrect time values days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'] months = ['Jan','Feb','Mar','Apr','May','Jun', \ 'Jul','Aug','Sep','Oct','Nov','Dec'] tz = ['UT','GMT','EST','EDT','CST','CDT','MST','MDT''PST','PDT'] ticket = Ticket(self.env) ticket['reporter'] = '"Joe User" <*****@*****.**>' ticket['summary'] = 'This is a summary' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) self.failIf('Date' not in headers) mo = date_re.match(headers['Date']) self.failIf(not mo) if mo.group('day'): self.failIf(mo.group('day') not in days) self.failIf(int(mo.group('dm')) not in range(1,32)) self.failIf(mo.group('month') not in months) self.failIf(int(mo.group('hour')) not in range(0,24)) if mo.group('tz'): self.failIf(mo.group('tz') not in tz)
def _test_updater(disable): if disable: self.env.config.set('notification', 'always_notify_updater', 'false') ticket = Ticket(self.env) ticket['reporter'] = '*****@*****.**' ticket['summary'] = u'This is a súmmäry' ticket['cc'] = '*****@*****.**' ticket.insert() ticket['component'] = 'dummy' now = datetime.now(utc) ticket.save_changes('*****@*****.**', 'This is a change', when=now) tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=now) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # checks for header existence self.failIf(not headers) # checks for updater in the 'To' recipient list self.failIf('To' not in headers) tolist = [addr.strip() for addr in headers['To'].split(',')] if disable: self.failIf('*****@*****.**' in tolist) else: self.failIf('*****@*****.**' not in tolist)
def test_recipients(self): """To/Cc recipients""" ticket = Ticket(self.env) ticket['reporter'] = '"Joe User" < *****@*****.** >' ticket['owner'] = '*****@*****.**' ticket['cc'] = '[email protected], [email protected], ' \ '*****@*****.**' ticket['summary'] = 'Foo' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) recipients = notifysuite.smtpd.get_recipients() # checks there is no duplicate in the recipient list rcpts = [] for r in recipients: self.failIf(r in rcpts) rcpts.append(r) # checks that all cc recipients have been notified cc_list = self.env.config.get('notification', 'smtp_always_cc') cc_list = "%s, %s" % (cc_list, ticket['cc']) for r in cc_list.replace(',', ' ').split(): self.failIf(r not in recipients) # checks that owner has been notified self.failIf(smtp_address(ticket['owner']) not in recipients) # checks that reporter has been notified self.failIf(smtp_address(ticket['reporter']) not in recipients)
def _test_short_login(enabled): ticket = Ticket(self.env) ticket['reporter'] = 'joeuser' ticket['summary'] = 'This is a summary' ticket.insert() # Be sure that at least one email address is valid, so that we # send a notification even if other addresses are not valid self.env.config.set('notification', 'smtp_always_cc', '*****@*****.**') if enabled: self.env.config.set('notification', 'use_short_addr', 'true') tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should not have a 'To' header if not enabled: self.failIf('To' in headers) else: tolist = [addr.strip() for addr in headers['To'].split(',')] # Msg should have a 'Cc' field self.failIf('Cc' not in headers) cclist = [addr.strip() for addr in headers['Cc'].split(',')] if enabled: # Msg should be delivered to the reporter self.failIf(ticket['reporter'] not in tolist) else: # Msg should not be delivered to joeuser self.failIf(ticket['reporter'] in cclist) # Msg should still be delivered to the always_cc list self.failIf(self.env.config.get('notification', 'smtp_always_cc') not in cclist)
def test_email_map(self): """Login-to-email mapping""" self.env.config.set('notification', 'always_notify_owner', 'true') self.env.config.set('notification', 'always_notify_reporter', 'true') self.env.config.set('notification', 'smtp_always_cc', '*****@*****.**') self.env.known_users = [ ('joeuser', 'Joe User', '*****@*****.**'), ('jim@domain', 'Jim User', '*****@*****.**') ] ticket = Ticket(self.env) ticket['reporter'] = 'joeuser' ticket['owner'] = 'jim@domain' ticket['summary'] = 'This is a summary' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should always have a 'To' field self.failIf('To' not in headers) tolist = [addr.strip() for addr in headers['To'].split(',')] # 'To' list should have been resolved to the real email address self.failIf('*****@*****.**' not in tolist) self.failIf('*****@*****.**' not in tolist) self.failIf('joeuser' in tolist) self.failIf('jim@domain' in tolist)
def _test_short_login(enabled): ticket = Ticket(self.env) ticket['reporter'] = 'joeuser' ticket['summary'] = 'This is a summary' ticket.insert() # Be sure that at least one email address is valid, so that we # send a notification even if other addresses are not valid self.env.config.set('notification', 'smtp_always_cc', '*****@*****.**') if enabled: self.env.config.set('notification', 'use_short_addr', 'true') tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should not have a 'To' header if not enabled: self.failIf('To' in headers) else: tolist = [addr.strip() for addr in headers['To'].split(',')] # Msg should have a 'Cc' field self.failIf('Cc' not in headers) cclist = [addr.strip() for addr in headers['Cc'].split(',')] if enabled: # Msg should be delivered to the reporter self.failIf(ticket['reporter'] not in tolist) else: # Msg should not be delivered to joeuser self.failIf(ticket['reporter'] in cclist) # Msg should still be delivered to the always_cc list self.failIf( self.env.config.get('notification', 'smtp_always_cc') not in cclist)
def create(self, req, summary, description, attributes={}, notify=False, when=None): """ Create a new ticket, returning the ticket ID. Overriding 'when' requires admin permission. """ t = model.Ticket(self.env) t['summary'] = summary t['description'] = description t['reporter'] = req.authname for k, v in attributes.iteritems(): t[k] = v t['status'] = 'new' t['resolution'] = '' # custom create timestamp? if when and not 'TICKET_ADMIN' in req.perm: self.log.warn( "RPC ticket.create: %r not allowed to create with " "non-current timestamp (%r)", req.authname, when) when = None t.insert(when=when) if notify: try: tn = TicketNotifyEmail(self.env) tn.notify(t, newticket=True) except Exception, e: self.log.exception("Failure sending notification on creation " "of ticket #%s: %s" % (t.id, e))
def _test_default_domain(enabled): self.env.config.set("notification", "always_notify_owner", "false") self.env.config.set("notification", "always_notify_reporter", "false") self.env.config.set("notification", "smtp_always_cc", "") ticket = Ticket(self.env) ticket["cc"] = "joenodom, [email protected]" ticket["summary"] = "This is a summary" ticket.insert() # Be sure that at least one email address is valid, so that we # send a notification even if other addresses are not valid self.env.config.set("notification", "smtp_always_cc", "*****@*****.**") if enabled: self.env.config.set("notification", "smtp_default_domain", "example.org") tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should always have a 'Cc' field self.failIf("Cc" not in headers) cclist = [addr.strip() for addr in headers["Cc"].split(",")] self.failIf("*****@*****.**" not in cclist) self.failIf("*****@*****.**" not in cclist) if not enabled: self.failIf(len(cclist) != 2) self.failIf("joenodom" in cclist) else: self.failIf(len(cclist) != 3) self.failIf("*****@*****.**" not in cclist)
def test_ignore_domains(self): """Non-SMTP domain exclusion""" self.env.config.set("notification", "ignore_domains", "example.com, example.org") self.env.known_users = [ ("*****@*****.**", "No Email", ""), ("*****@*****.**", "With Email", "*****@*****.**"), ] ticket = Ticket(self.env) ticket["reporter"] = "*****@*****.**" ticket["owner"] = "*****@*****.**" ticket["summary"] = "This is a summary" ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should always have a 'To' field self.failIf("To" not in headers) tolist = [addr.strip() for addr in headers["To"].split(",")] # 'To' list should not contain addresses with non-SMTP domains self.failIf("*****@*****.**" in tolist) self.failIf("*****@*****.**" in tolist) # 'To' list should have been resolved to the actual email address self.failIf("*****@*****.**" not in tolist) self.failIf(len(tolist) != 1)
def test_date(self): """Date format compliance (RFC822) we do not support 'military' format""" date_str = r"^((?P<day>\w{3}),\s*)*(?P<dm>\d{2})\s+" \ r"(?P<month>\w{3})\s+(?P<year>\d{4})\s+" \ r"(?P<hour>\d{2}):(?P<min>[0-5][0-9])" \ r"(:(?P<sec>[0-5][0-9]))*\s" \ r"((?P<tz>\w{2,3})|(?P<offset>[+\-]\d{4}))$" date_re = re.compile(date_str) # python time module does not detect incorrect time values days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', \ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] tz = [ 'UT', 'GMT', 'EST', 'EDT', 'CST', 'CDT', 'MST', 'MDT', 'PST', 'PDT' ] ticket = Ticket(self.env) ticket['reporter'] = '"Joe User" <*****@*****.**>' ticket['summary'] = 'This is a summary' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) self.failIf('Date' not in headers) mo = date_re.match(headers['Date']) self.failIf(not mo) if mo.group('day'): self.failIf(mo.group('day') not in days) self.failIf(int(mo.group('dm')) not in range(1, 32)) self.failIf(mo.group('month') not in months) self.failIf(int(mo.group('hour')) not in range(0, 24)) if mo.group('tz'): self.failIf(mo.group('tz') not in tz)
def test_email_map(self): """Login-to-email mapping""" self.env.config.set("notification", "always_notify_owner", "true") self.env.config.set("notification", "always_notify_reporter", "true") self.env.config.set("notification", "smtp_always_cc", "*****@*****.**") self.env.known_users = [ ("joeuser", "Joe User", "*****@*****.**"), ("jim@domain", "Jim User", "*****@*****.**"), ] ticket = Ticket(self.env) ticket["reporter"] = "joeuser" ticket["owner"] = "jim@domain" ticket["summary"] = "This is a summary" ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should always have a 'To' field self.failIf("To" not in headers) tolist = [addr.strip() for addr in headers["To"].split(",")] # 'To' list should have been resolved to the real email address self.failIf("*****@*****.**" not in tolist) self.failIf("*****@*****.**" not in tolist) self.failIf("joeuser" in tolist) self.failIf("jim@domain" in tolist)
def _test_short_login(enabled): ticket = Ticket(self.env) ticket["reporter"] = "joeuser" ticket["summary"] = "This is a summary" ticket.insert() # Be sure that at least one email address is valid, so that we # send a notification even if other addresses are not valid self.env.config.set("notification", "smtp_always_cc", "*****@*****.**") if enabled: self.env.config.set("notification", "use_short_addr", "true") tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) # Msg should not have a 'To' header if not enabled: self.failIf("To" in headers) else: tolist = [addr.strip() for addr in headers["To"].split(",")] # Msg should have a 'Cc' field self.failIf("Cc" not in headers) cclist = [addr.strip() for addr in headers["Cc"].split(",")] if enabled: # Msg should be delivered to the reporter self.failIf(ticket["reporter"] not in tolist) else: # Msg should not be delivered to joeuser self.failIf(ticket["reporter"] in cclist) # Msg should still be delivered to the always_cc list self.failIf(self.env.config.get("notification", "smtp_always_cc") not in cclist)
def _save_ticket_changes(self, req, env, log, selectedTickets, tickets, values, comment, modify_changetime, send_notifications): for id in selectedTickets: if id in tickets: t = Ticket(env, int(id)) new_changetime = datetime.now(utc) log_msg = "" if not modify_changetime: original_changetime = to_timestamp(t.time_changed) _values = values.copy() for field in [f for f in values.keys() \ if f in self._fields_as_list]: _values[field] = self._merge_keywords(t.values[field], values[field], log) t.populate(_values) t.save_changes(req.authname, comment, when=new_changetime) if send_notifications: tn = TicketNotifyEmail(env) tn.notify(t, newticket=0, modtime=new_changetime) if not modify_changetime: self._reset_changetime(env, original_changetime, t) log_msg = "(changetime not modified)" log.debug('BatchModifyPlugin: saved changes to #%s %s' % (id, log_msg))
def create(self, req, summary, description, attributes={}, notify=False): """ Create a new ticket, returning the ticket ID. PS: Borrowed from XmlRpcPlugin. """ if 'product' in attributes: env = self.env.parent or self.env if attributes['product']: env = ProductEnvironment(env, attributes['product']) else: env = self.env t = Ticket(env) t['summary'] = summary t['description'] = description t['reporter'] = req.authname for k, v in attributes.iteritems(): t[k] = v t['status'] = 'new' t['resolution'] = '' t.insert() if notify: try: tn = TicketNotifyEmail(env) tn.notify(t, newticket=True) except Exception, e: self.log.exception("Failure sending notification on creation " "of ticket #%s: %s" % (t.id, e))
def _implementation(db): for id in selectedTickets: if id in tickets: t = Ticket(env, int(id)) new_changetime = datetime.now(utc) log_msg = "" if not modify_changetime: original_changetime = to_utimestamp(t.time_changed) _values = new_values.copy() for field in [f for f in new_values.keys() \ if f in self._fields_as_list]: _values[field] = self._merge_keywords( t.values[field], new_values[field], log) t.populate(_values) t.save_changes(req.authname, comment, when=new_changetime) if send_notifications: tn = TicketNotifyEmail(env) tn.notify(t, newticket=0, modtime=new_changetime) if not modify_changetime: self._reset_changetime(env, original_changetime, t) log_msg = "(changetime not modified)" log.debug('BatchModifyPlugin: saved changes to #%s %s' % (id, log_msg))
def post_to_ticket(msg, author, tkt_id, env): """Post the message to the ticket and send a notify email.""" from trac.ticket.notification import TicketNotifyEmail from trac.ticket import Ticket from trac.ticket.web_ui import TicketModule from trac.util.datefmt import utc now = datetime.now(utc) try: db = env.get_db_cnx() # Get the related trac ticket object ticket = Ticket(env, tkt_id, db) # determine sequence number... cnum = 0 tm = TicketModule(env) for change in tm.grouped_changelog_entries(ticket, db): if change['permanent']: cnum += 1 ticket.save_changes(author, msg, now, db, cnum + 1) db.commit() tn = TicketNotifyEmail(env) tn.notify(ticket, newticket=0, modtime=now) except Exception, e: msg = 'Unexpected error processing ticket ID %s: %s' % (tkt_id, e) print >>sys.stderr, msg
def save_ticket(self, tckt, db, msg): # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(tckt, db): if change['permanent']: cnum += 1 tckt.save_changes(self.authname, msg, self.now, db, cnum+1) ## Often the time overlaps and causes a db error, ## especially when the trac integration post-commit hook is used. ## NOTE TO SELF. I DON'T THINK THIS IS NECESSARY RIGHT NOW... #count = 0 #while count < 10: # try: # tckt.save_changes(self.authname, msg, self.now, db, cnum+1) # count = 42 # except Exception, e: # self.now += 1 # count += 1 db.commit() tn = TicketNotifyEmail(self.env) tn.notify(tckt, newticket=0, modtime=self.now) # We fudge time as it has to be unique self.now += 1
def ticket_changed(self,ticket,comment,author,old_values): self.env.log.debug("ticket_change - TicketNotifySMS: %s" % author) # Q) why does debug work on DEBUG setting but not INFO? db = self.env.get_db_cnx() cursor = db.cursor() sql = "select field, newvalue from ticket_change where ticket = %s ORDER BY time DESC LIMIT 1" % ticket.id cursor.execute(sql) data = cursor.fetchall() msg = '' for row in data: # TODO check alerts aren't needed on other fields if row[0] == 'comment': patt = re.compile('{{{(.+)}}}') mobj = patt.match(row[1]) self.env.log.debug('comment value: ' + row[1]) body = '' try: body = mobj.group(0) except AttributeError: self.env.log.debug('no brackets') body = row[1] msg = "Re: shot %s - %s" % (ticket.values['summary'], body ) # ticket.id if necessary tne = TicketNotifyEmail(self.env) peeps = tne.get_recipients(ticket.id) list = {} for person in peeps: for p in person: list[p] = 1 for k in list.keys(): self.env.log.debug("recepient: %s" % k) if k != None: self.sms(k, str(ticket.time_changed), ticket.values['summary'], msg)
def add_tickets(self, project, customerrequest, tickets, reporter, notify=False): from trac.ticket.notification import TicketNotifyEmail from trac.util.text import exception_to_unicode from penelope.core.models.dashboard import User settings = get_current_registry().settings tracenvs = settings.get('penelope.trac.envs') request = get_current_request() for trac in project.tracs: for t in tickets: owner = DBSession.query(User).get(t['owner']) ticket = {'summary': t['summary'], 'description': t['description'], 'customerrequest': customerrequest.id, 'reporter': reporter.email, 'type': 'task', 'priority': 'major', 'milestone': 'Backlog', 'owner': owner.email, 'status': 'new'} tracenv = Environment('%s/%s' % (tracenvs, trac.trac_name)) tracenv.abs_href.base = trac.api_uri t = Ticket(tracenv) t.populate(ticket) t.insert() if notify: try: tn = TicketNotifyEmail(tracenv) tn.notify(t, newticket=True) except Exception, e: request.add_message('Failure sending notification on creation ' 'of a ticket #%s: %s' % (t.id, exception_to_unicode(e)), 'error')
def test_date(self): """Date format compliance (RFC822) we do not support 'military' format""" date_str = ( r"^((?P<day>\w{3}),\s*)*(?P<dm>\d{2})\s+" r"(?P<month>\w{3})\s+(?P<year>\d{4})\s+" r"(?P<hour>\d{2}):(?P<min>[0-5][0-9])" r"(:(?P<sec>[0-5][0-9]))*\s" r"((?P<tz>\w{2,3})|(?P<offset>[+\-]\d{4}))$" ) date_re = re.compile(date_str) # python time module does not detect incorrect time values days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] tz = ["UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT"] ticket = Ticket(self.env) ticket["reporter"] = '"Joe User" <*****@*****.**>' ticket["summary"] = "This is a summary" ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message) self.failIf("Date" not in headers) mo = date_re.match(headers["Date"]) self.failIf(not mo) if mo.group("day"): self.failIf(mo.group("day") not in days) self.failIf(int(mo.group("dm")) not in range(1, 32)) self.failIf(mo.group("month") not in months) self.failIf(int(mo.group("hour")) not in range(0, 24)) if mo.group("tz"): self.failIf(mo.group("tz") not in tz)
def attachment_added(self, attachment): # Check whether we're dealing with a ticket resource resource = attachment.resource while resource: if resource.realm == 'ticket': break resource = resource.parent if (resource and resource.realm == 'ticket' and resource.id is not None): with self.env.db_transaction as db: ticket = Ticket(attachment.env, resource.id, db) if (attachment.author == ticket['reporter'] and ticket['status'] == 'pending'): self.env.log.info('Removing Pending status for ticket %s due to attachment' % (ticket.id)) comment = 'Attachment (%s) added by ticket reporter.' % (attachment.filename) ticket['status'] = self.config.get('ticket', 'pending_removal_status') # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(ticket, db): c_cnum = change.get('cnum', None) if c_cnum and int(c_cnum) > cnum: cnum = int(c_cnum) #We can't just use attachment.date as it screws up event sequencing now = datetime.now(utc) ticket.save_changes(attachment.author, comment, now, db, str(cnum + 1)) #trigger notification since we've changed the ticket tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=now)
def process(self, commit, status, branch): self.closestatus = status milestones = [ m.name for m in Milestone.select(self.env) if m.name != 'unknown' ] if branch.startswith('fixes/'): branch = branch[6:] milestones = [m for m in milestones if m.startswith(branch)] self.milestone = sorted(milestones)[-1] msg = commit['message'] self.env.log.debug("Processing Commit: %s", msg) msg = "%s \n Branch: %s \n Changeset: %s" % (msg, branch, commit['id']) # author = commit['author']['name'] author = 'Github' timestamp = datetime.now(utc) cmd_groups = command_re.findall(msg) self.env.log.debug("Function Handlers: %s" % cmd_groups) tickets = {} for cmd, tkts in cmd_groups: funcname = self.__class__._supported_cmds.get(cmd.lower(), '') self.env.log.debug("Function Handler: %s" % funcname) if funcname: for tkt_id in ticket_re.findall(tkts): if (branch == "master") or branch.startswith("fixes/"): tickets.setdefault(tkt_id, []).append(getattr(self, funcname)) # disable this stuff for now, it causes duplicates on merges # proper implementation of this will require tracking commit hashes # else: # tickets.setdefault(tkt_id, []).append(self._cmdRefs) for tkt_id, cmds in tickets.iteritems(): try: db = self.env.get_db_cnx() ticket = Ticket(self.env, int(tkt_id), db) for cmd in cmds: cmd(ticket) # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(ticket, db): if change['permanent']: cnum += 1 ticket.save_changes(author, msg, timestamp, db, cnum + 1) db.commit() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=0, modtime=timestamp) except Exception, e: import traceback traceback.print_exc(file=sys.stderr)
def _do_save(self, req, db, ticket): if req.perm.has_permission('TICKET_CHGPROP'): # TICKET_CHGPROP gives permission to edit the ticket if not req.args.get('summary'): raise TracError(u'Les tickets doivent contenir un intitulé.') if req.args.has_key('description') or req.args.has_key('reporter'): req.perm.assert_permission('TICKET_ADMIN') ticket.populate(req.args) else: req.perm.assert_permission('TICKET_APPEND') # Mid air collision? if int(req.args.get('ts')) != ticket.time_changed: raise TracError(u"Désolé, impossible d'enregistrer vos modifications. " u"Ce ticket a été modifié par quelqu'un d'autre " u"depuis que vous avez commencé", u'Collision en plein vol') # Do any action on the ticket? action = req.args.get('action') actions = TicketSystem(self.env).get_available_actions(ticket, req.perm) if action not in actions: raise TracError(u'Action invalide') # TODO: this should not be hard-coded like this if action == 'accept': ticket['status'] = 'assigned' ticket['owner'] = req.authname if action == 'resolve': ticket['status'] = 'closed' ticket['resolution'] = req.args.get('resolve_resolution') elif action == 'reassign': ticket['owner'] = req.args.get('reassign_owner') ticket['status'] = 'new' elif action == 'reopen': ticket['status'] = 'reopened' ticket['resolution'] = '' self._validate_ticket(req, ticket) now = int(time.time()) cnum = req.args.get('cnum') replyto = req.args.get('replyto') internal_cnum = cnum if cnum and replyto: # record parent.child relationship internal_cnum = '%s.%s' % (replyto, cnum) if ticket.save_changes(get_reporter_id(req, 'author'), req.args.get('comment'), when=now, db=db, cnum=internal_cnum): db.commit() try: tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=now) except Exception, e: self.log.exception("Failure sending notification on change to " "ticket #%s: %s" % (ticket.id, e))
def _do_save(self, req, db, ticket): if req.perm.has_permission('TICKET_CHGPROP'): # TICKET_CHGPROP gives permission to edit the ticket if not req.args.get('summary'): raise TracError('Tickets must contain summary.') if req.args.has_key('description') or req.args.has_key('reporter'): req.perm.assert_permission('TICKET_ADMIN') ticket.populate(req.args) else: req.perm.assert_permission('TICKET_APPEND') # Mid air collision? if int(req.args.get('ts')) != ticket.time_changed: raise TracError("Sorry, can not save your changes. " "This ticket has been modified by someone else " "since you started", 'Mid Air Collision') # Do any action on the ticket? action = req.args.get('action') actions = TicketSystem(self.env).get_available_actions(ticket, req.perm) if action not in actions: raise TracError('Invalid action') # TODO: this should not be hard-coded like this if action == 'accept': ticket['status'] = 'assigned' ticket['owner'] = req.authname if action == 'resolve': ticket['status'] = 'closed' ticket['resolution'] = req.args.get('resolve_resolution') elif action == 'reassign': ticket['owner'] = req.args.get('reassign_owner') ticket['status'] = 'new' elif action == 'reopen': ticket['status'] = 'reopened' ticket['resolution'] = '' self._validate_ticket(req, ticket) now = int(time.time()) cnum = req.args.get('cnum') replyto = req.args.get('replyto') internal_cnum = cnum if cnum and replyto: # record parent.child relationship internal_cnum = '%s.%s' % (replyto, cnum) if ticket.save_changes(get_reporter_id(req, 'author'), req.args.get('comment'), when=now, db=db, cnum=internal_cnum): db.commit() try: tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=now) except Exception, e: self.log.exception("Failure sending notification on change to " "ticket #%s: %s" % (ticket.id, e))
def notify(self, env, tkt, new=True, modtime=0): """ A Wrapper for TRAC notify function """ try: # create false {abs_}href properties, to trick Notify() # tn = TicketNotifyEmail(env) tn.notify(tkt, new, modtime) except Exception, e: print 'TD: Failure sending notification on creation of ticket #%s: %s' %(tkt['id'], e)
def test_notification_get_message_id_unicode(self): ticket = Ticket(self.env) ticket['summary'] = 'My Summary' ticket['description'] = 'Some description' ticket.insert() self.env.config.set('project', 'url', u"пиво Müller ") tn = TicketNotifyEmail(self.env) tn.ticket = ticket tn.get_message_id('foo')
def test_notification_get_message_id_unicode(self): ticket = Ticket(self.env) ticket["summary"] = "My Summary" ticket["description"] = "Some description" ticket.insert() self.env.config.set("project", "url", u"пиво Müller ") tn = TicketNotifyEmail(self.env) tn.ticket = ticket tn.get_message_id("foo")
def __init__(self, project=options.project, author=AUTHOR, maxage=options.maxage, url=options.url): self.env = open_environment(project) db = self.env.get_db_cnx() cursor = db.cursor() if url is None: url = self.env.config.get('trac', 'base_url') self.env.href = Href(url) self.env.abs_href = Href(url) self.msg = MESSAGE % (maxage) self.now = int(time.time()) maxtime = int(time.time()) - (60 * 60 * 24 * maxage) cursor.execute("SELECT id FROM ticket t, ticket_custom c " \ "WHERE t.status <> %s " \ "AND t.changetime < %s " \ "AND t.id = c.ticket " \ "AND c.name = %s " \ "AND c.value = %s ", ('closed', maxtime, 'pending', '1')) rows = cursor.fetchall() for row in rows: id = row[0] try: ticket = Ticket(self.env, id, db) ticket['status'] = 'closed' ticket['pending'] = '0' # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(ticket, db): if change['permanent']: cnum += 1 ticket.save_changes(author, self.msg, self.now, db, cnum + 1) db.commit() print 'Closing Ticket %s (%s)\n' % (id, ticket['summary']) tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=0, modtime=self.now) except Exception, e: import traceback traceback.print_exc(file=sys.stderr) print>>sys.stderr, 'Unexpected error while processing ticket ' \ 'ID %s: %s' % (id, e)
def __init__(self, project=options.project, author=options.user, rev=options.rev, url=options.url): self.env = open_environment(project) repos = self.env.get_repository() repos.sync() # Instead of bothering with the encoding, we'll use unicode data # as provided by the Trac versioncontrol API (#1310). try: chgset = repos.get_changeset(rev) except NoSuchChangeset: return # out of scope changesets are not cached self.author = chgset.author self.rev = rev self.msg = "(In [%s]) %s" % (rev, chgset.message) self.now = datetime.now(utc) cmd_groups = command_re.findall(self.msg) tickets = {} for cmd, tkts in cmd_groups: funcname = CommitHook._supported_cmds.get(cmd.lower(), '') if funcname: for tkt_id in ticket_re.findall(tkts): func = getattr(self, funcname) tickets.setdefault(tkt_id, []).append(func) for tkt_id, cmds in tickets.iteritems(): try: db = self.env.get_db_cnx() ticket = Ticket(self.env, int(tkt_id), db) for cmd in cmds: cmd(ticket) # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(ticket, db): if change['permanent']: cnum += 1 ticket.save_changes(self.author, self.msg, self.now, db, cnum + 1) db.commit() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=0, modtime=self.now) except Exception, e: # import traceback # traceback.print_exc(file=sys.stderr) print>>sys.stderr, 'Unexpected error while processing ticket ' \ 'ID %s: %s' % (tkt_id, e)
def process(self, commit, status, branch): self.closestatus = status milestones = [m.name for m in Milestone.select(self.env) if m.name != "unknown"] if branch.startswith("fixes/"): branch = branch[6:] milestones = [m for m in milestones if m.startswith(branch)] self.milestone = sorted(milestones)[-1] msg = commit["message"] self.env.log.debug("Processing Commit: %s", msg) msg = "%s \n Branch: %s \n Changeset: %s" % (msg, branch, commit["id"]) # author = commit['author']['name'] author = "Github" timestamp = datetime.now(utc) cmd_groups = command_re.findall(msg) self.env.log.debug("Function Handlers: %s" % cmd_groups) tickets = {} for cmd, tkts in cmd_groups: funcname = self.__class__._supported_cmds.get(cmd.lower(), "") self.env.log.debug("Function Handler: %s" % funcname) if funcname: for tkt_id in ticket_re.findall(tkts): if (branch == "master") or branch.startswith("fixes/"): tickets.setdefault(tkt_id, []).append(getattr(self, funcname)) # disable this stuff for now, it causes duplicates on merges # proper implementation of this will require tracking commit hashes # else: # tickets.setdefault(tkt_id, []).append(self._cmdRefs) for tkt_id, cmds in tickets.iteritems(): try: db = self.env.get_db_cnx() ticket = Ticket(self.env, int(tkt_id), db) for cmd in cmds: cmd(ticket) # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(ticket, db): if change["permanent"]: cnum += 1 ticket.save_changes(author, msg, timestamp, db, cnum + 1) db.commit() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=0, modtime=timestamp) except Exception, e: import traceback traceback.print_exc(file=sys.stderr)
def _do_create(self, req, ticket): ticket.insert() # Notify try: tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) except Exception, e: self.log.error("""Failure sending notification on creation of ticket #%s: %s""", ticket.id, e)
def notify(self, env, tkt, new=True, modtime=0): """ A Wrapper for TRAC notify function """ try: # create false {abs_}href properties, to trick Notify() # tn = TicketNotifyEmail(env) tn.notify(tkt, new, modtime) except Exception, e: print 'TD: Failure sending notification on creation of ticket #%s: %s' % ( tkt['id'], e)
def _notify(self, ticket, date): """Send a ticket update notification.""" if not self.notify: return try: tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=date) except Exception, e: self.log.error( "Failure sending notification on change to " "ticket #%s: %s", ticket.id, exception_to_unicode(e))
def process_message(self, req, msgstr): project_list = get_project_list(self.env, req, return_self=True, include_errors=False) msg = email.message_from_string(msgstr) msg_from = parseaddr(msg.get("from"))[1] msg_subject = msg.get("subject") in_reply_to = msg.get("in-reply-to", "") msg_content = "" if not msg.is_multipart(): msg_content = msg.get_payload(decode=True) else: for part in msg.walk(): if part.get_content_type() == 'text/plain': msg_content = part.get_payload(decode=True) msg_content = to_unicode(msg_content) match = INREPLYTO_TICKET_EXPR.match(in_reply_to) if match: for project, project_path, project_url, project_env in project_list: if not project_env: continue if os.path.basename(project_path).lower() != match.group( 'base').lower(): continue ticket = Ticket(project_env, int(match.group('id'))) now = datetime.now(utc) ticket.save_changes(msg_from, msg_content, when=now) #----- Copiado de web_ui.py ----- try: tn = TicketNotifyEmail(project_env) tn.notify(ticket, newticket=False, modtime=now) except Exception, e: self.log.error( "Failure sending notification on change to " "ticket #%s: %s", ticket.id, exception_to_unicode(e)) ## After saving the changes, apply the side-effects. #for controller in controllers: # self.env.log.debug('Side effect for %s' % # controller.__class__.__name__) #----- Fin Copiado de web_ui.py ----- return (True, "Ticket reply match - %s#%s" % (match.group('base'), match.group('id')))
def process(self, commit, status, enable_revmap, reponame): self.closestatus = status msg = commit['message'] self.env.log.debug("Processing Commit: %s", msg) note = "Changeset: [/changeset/%s %s]" % (commit['id'], commit['id']) url = "URL: %s" % commit['url'] msg = "%s \n * %s \n * %s" % (msg, note, url) author = commit['author']['name'] timestamp = datetime.now(utc) if int(enable_revmap): self.env.log.debug("adding commit %s to revmap", commit['id']) db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute( "INSERT INTO svn_revmap (svn_rev, git_hash, commit_msg) VALUES (0, %s, %s);", (commit['id'], commit['message'])) db.commit() cmd_groups = command_re.findall(msg) self.env.log.debug("Function Handlers: %s" % cmd_groups) tickets = {} for cmd, tkts in cmd_groups: funcname = self.__class__._supported_cmds.get(cmd.lower(), '') self.env.log.debug("Function Handler: %s" % funcname) if funcname: for tkt_id in ticket_re.findall(tkts): func = getattr(self, funcname) tickets.setdefault(tkt_id, []).append(func) for tkt_id, cmds in tickets.iteritems(): try: db = self.env.get_db_cnx() ticket = Ticket(self.env, int(tkt_id), db) for cmd in cmds: cmd(ticket) # determine sequence number... cnum = 0 tm = TicketModule(self.env) for change in tm.grouped_changelog_entries(ticket, db): if change['permanent']: cnum += 1 ticket.save_changes(author, msg, timestamp, db, cnum + 1) db.commit() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=0, modtime=timestamp) except Exception, e: import traceback traceback.print_exc(file=sys.stderr)
def _do_create(self, req, ticket): ticket.insert() # Notify try: tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) except Exception, e: self.log.error( """Failure sending notification on creation of ticket #%s: %s""", ticket.id, e)
def test_cc_only(self): """Notification w/o explicit recipients but Cc: (#3101)""" ticket = Ticket(self.env) ticket['summary'] = 'Foo' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) recipients = notifysuite.smtpd.get_recipients() # checks that all cc recipients have been notified cc_list = self.env.config.get('notification', 'smtp_always_cc') for r in cc_list.replace(',', ' ').split(): self.failIf(r not in recipients)
def test_notification_does_not_alter_ticket_instance(self): ticket = Ticket(self.env) ticket['summary'] = 'My Summary' ticket['description'] = 'Some description' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) self.assertNotEqual(None, notifysuite.smtpd.get_message()) self.assertEqual('My Summary', ticket['summary']) self.assertEqual('Some description', ticket['description']) valid_fieldnames = set([f['name'] for f in ticket.fields]) current_fieldnames = set(ticket.values.keys()) self.assertEqual(set(), current_fieldnames - valid_fieldnames)
def test_md5_digest(self): """MD5 digest w/ non-ASCII recipient address (#3491)""" self.env.config.set('notification', 'always_notify_owner', 'false') self.env.config.set('notification', 'always_notify_reporter', 'true') self.env.config.set('notification', 'smtp_always_cc', '') ticket = Ticket(self.env) ticket['reporter'] = u'"Jöe Usèr" <*****@*****.**>' ticket['summary'] = u'This is a summary' ticket.insert() tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=True) message = notifysuite.smtpd.get_message() (headers, body) = parse_smtp_message(message)
def send_notification(self, ticket, author): if TicketNotifyEmail: tn = TicketNotifyEmail(self.env) tn.notify(ticket, newticket=False, modtime=ticket['changetime']) else: event = TicketChangeEvent('changed', ticket, ticket['changetime'], author) try: NotificationSystem(self.env).notify(event) except Exception as e: self.log.error( "Failure sending notification on change to " "ticket #%s: %s", ticket.id, exception_to_unicode(e))