Am Mittwoch, 8. März 2017 21:32:45 UTC+1 schrieb Peter Suter:
>
> What plugins do you use? Can you reproduce with all plugins disabled? Do
> you have more than one active INotificationDistributor that supports
> transport email?
>
My_NotificationSubscriber.py
FieldTooltip-0.6-py2.7.egg
SimpleMultiProject-0.5.2.dev0-py2.7.egg
TracAutocompleteUsersPlugin-0.4.4.dev0-py2.7.egg
TracCodeReviewer-1.0.0.dev0-py2.7.egg
TracDiscussion-0.10.0-py2.7.egg
TracDynamicFields-2.2.0.dev0-py2.7.egg
TracFullBlogPlugin-0.1.5-py2.7.egg
TracGanttCalendarPlugin-0.6.4.post0-py2.7.egg
TracHtmlNotificationPlugin-0.12.0.1-py2.7.egg
TracIncludeMacro-3.0.0.dev0-py2.7.egg
Trac_jsGantt-0.11.post0-py2.7.egg
trac_NewTicketLikeThisPlugin-0.2-py2.7.egg
TracQuiet-1.2.0.dev0-py2.7.egg
TracSubTicketsPlugin-0.4.1-py2.7.egg
TracTicketFieldsLayoutPlugin-0.12.0.2-py2.7.egg
TracWikiExtras-1.3.1.dev0-py2.7.egg
TracWorkflowAdmin-0.12.0.3-py2.7.egg
WikiAutoComplete-1.1-py2.7.egg
With this custom notifications in My_NotificationSubscriber.py:
from trac.core import Component, implements
from trac.ticket.api import TicketSystem
from trac.notification.api import INotificationSubscriber,
NotificationSystem
from trac.notification.mail import RecipientMatcher
from trac.notification.model import Subscription
from trac.web.chrome import Chrome
class AuthorCustomFieldSubscriber(Component):
"""Subscriber for custom ticket field."""
implements(INotificationSubscriber)
field_name = 'author'
def matches(self, event):
if event.realm != 'ticket':
return
if event.category not in ('created', 'changed', 'attachment added',
'attachment deleted'):
return
# Custom field with comma-separated string. Parse to set.
chrome = Chrome(self.env)
to_set = lambda field: set(chrome.cc_list(field))
field_set = to_set(event.target[self.field_name] or '')
# Harvest previous field values
if 'fields' in event.changes and self.field_name in event.changes[
'fields']:
field_set.update(to_set(event.changes['fields'][self.field_name][
'old']))
matcher = RecipientMatcher(self.env)
klass = self.__class__.__name__
sids = set()
for field in field_set:
recipient = matcher.match_recipient(field)
if not recipient:
continue
sid, auth, addr = recipient
# Default subscription
for s in self.default_subscriptions():
yield s[0], s[1], sid, auth, addr, s[2], s[3], s[4]
if sid:
sids.add((sid, auth))
for s in Subscription.find_by_sids_and_class(self.env, sids, klass):
yield s.subscription_tuple()
def description(self):
ticket_system = TicketSystem(self.env)
ticket_field_labels = ticket_system.get_ticket_field_labels()
field_label = ticket_field_labels[self.field_name]
return "Ticket that I'm listed in as %s is modified. [custom]" %
field_label
def default_subscriptions(self):
klass = self.__class__.__name__
return NotificationSystem(self.env).default_subscriptions(klass)
def requires_authentication(self):
return True
class ReviewerCustomFieldSubscriber(Component):
"""Subscriber for custom ticket field."""
implements(INotificationSubscriber)
field_name = 'reviewer'
def matches(self, event):
if event.realm != 'ticket':
return
if event.category not in ('created', 'changed', 'attachment added',
'attachment deleted'):
return
# Custom field with comma-separated string. Parse to set.
chrome = Chrome(self.env)
to_set = lambda field: set(chrome.cc_list(field))
field_set = to_set(event.target[self.field_name] or '')
# Harvest previous field values
if 'fields' in event.changes and self.field_name in event.changes[
'fields']:
field_set.update(to_set(event.changes['fields'][self.field_name][
'old']))
matcher = RecipientMatcher(self.env)
klass = self.__class__.__name__
sids = set()
for field in field_set:
recipient = matcher.match_recipient(field)
if not recipient:
continue
sid, auth, addr = recipient
# Default subscription
for s in self.default_subscriptions():
yield s[0], s[1], sid, auth, addr, s[2], s[3], s[4]
if sid:
sids.add((sid, auth))
for s in Subscription.find_by_sids_and_class(self.env, sids, klass):
yield s.subscription_tuple()
def description(self):
ticket_system = TicketSystem(self.env)
ticket_field_labels = ticket_system.get_ticket_field_labels()
field_label = ticket_field_labels[self.field_name]
return "Ticket that I'm listed in as %s is modified. [custom]" %
field_label
def default_subscriptions(self):
klass = self.__class__.__name__
return NotificationSystem(self.env).default_subscriptions(klass)
def requires_authentication(self):
return True
class DeveloperCustomFieldSubscriber(Component):
"""Subscriber for custom ticket field."""
implements(INotificationSubscriber)
field_name = 'developer'
def matches(self, event):
if event.realm != 'ticket':
return
if event.category not in ('created', 'changed', 'attachment added',
'attachment deleted'):
return
# Custom field with comma-separated string. Parse to set.
chrome = Chrome(self.env)
to_set = lambda field: set(chrome.cc_list(field))
field_set = to_set(event.target[self.field_name] or '')
# Harvest previous field values
if 'fields' in event.changes and self.field_name in event.changes[
'fields']:
field_set.update(to_set(event.changes['fields'][self.field_name][
'old']))
matcher = RecipientMatcher(self.env)
klass = self.__class__.__name__
sids = set()
for field in field_set:
recipient = matcher.match_recipient(field)
if not recipient:
continue
sid, auth, addr = recipient
# Default subscription
for s in self.default_subscriptions():
yield s[0], s[1], sid, auth, addr, s[2], s[3], s[4]
if sid:
sids.add((sid, auth))
for s in Subscription.find_by_sids_and_class(self.env, sids, klass):
yield s.subscription_tuple()
def description(self):
ticket_system = TicketSystem(self.env)
ticket_field_labels = ticket_system.get_ticket_field_labels()
field_label = ticket_field_labels[self.field_name]
return "Ticket that I'm listed in as %s is modified. [custom]" %
field_label
def default_subscriptions(self):
klass = self.__class__.__name__
return NotificationSystem(self.env).default_subscriptions(klass)
def requires_authentication(self):
return True
class TesterCustomFieldSubscriber(Component):
"""Subscriber for custom ticket field."""
implements(INotificationSubscriber)
field_name = 'tester'
def matches(self, event):
if event.realm != 'ticket':
return
if event.category not in ('created', 'changed', 'attachment added',
'attachment deleted'):
return
# Custom field with comma-separated string. Parse to set.
chrome = Chrome(self.env)
to_set = lambda field: set(chrome.cc_list(field))
field_set = to_set(event.target[self.field_name] or '')
# Harvest previous field values
if 'fields' in event.changes and self.field_name in event.changes[
'fields']:
field_set.update(to_set(event.changes['fields'][self.field_name][
'old']))
matcher = RecipientMatcher(self.env)
klass = self.__class__.__name__
sids = set()
for field in field_set:
recipient = matcher.match_recipient(field)
if not recipient:
continue
sid, auth, addr = recipient
# Default subscription
for s in self.default_subscriptions():
yield s[0], s[1], sid, auth, addr, s[2], s[3], s[4]
if sid:
sids.add((sid, auth))
for s in Subscription.find_by_sids_and_class(self.env, sids, klass):
yield s.subscription_tuple()
def description(self):
ticket_system = TicketSystem(self.env)
ticket_field_labels = ticket_system.get_ticket_field_labels()
field_label = ticket_field_labels[self.field_name]
return "Ticket that I'm listed in as %s is modified. [custom]" %
field_label
def default_subscriptions(self):
klass = self.__class__.__name__
return NotificationSystem(self.env).default_subscriptions(klass)
def requires_authentication(self):
return True
class IntegratorCustomFieldSubscriber(Component):
"""Subscriber for custom ticket field."""
implements(INotificationSubscriber)
field_name = 'integrator'
def matches(self, event):
if event.realm != 'ticket':
return
if event.category not in ('created', 'changed', 'attachment added',
'attachment deleted'):
return
# Custom field with comma-separated string. Parse to set.
chrome = Chrome(self.env)
to_set = lambda field: set(chrome.cc_list(field))
field_set = to_set(event.target[self.field_name] or '')
# Harvest previous field values
if 'fields' in event.changes and self.field_name in event.changes[
'fields']:
field_set.update(to_set(event.changes['fields'][self.field_name][
'old']))
matcher = RecipientMatcher(self.env)
klass = self.__class__.__name__
sids = set()
for field in field_set:
recipient = matcher.match_recipient(field)
if not recipient:
continue
sid, auth, addr = recipient
# Default subscription
for s in self.default_subscriptions():
yield s[0], s[1], sid, auth, addr, s[2], s[3], s[4]
if sid:
sids.add((sid, auth))
for s in Subscription.find_by_sids_and_class(self.env, sids, klass):
yield s.subscription_tuple()
def description(self):
ticket_system = TicketSystem(self.env)
ticket_field_labels = ticket_system.get_ticket_field_labels()
field_label = ticket_field_labels[self.field_name]
return "Ticket that I'm listed in as %s is modified. [custom]" %
field_label
def default_subscriptions(self):
klass = self.__class__.__name__
return NotificationSystem(self.env).default_subscriptions(klass)
def requires_authentication(self):
return True
Can you see anything (including the config) that could trigger duplicate
emails?
Best regards,
Mo
--
You received this message because you are subscribed to the Google Groups "Trac
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/trac-users.
For more options, visit https://groups.google.com/d/optout.