= Flexible notifications for Trac = == Description == The AnnouncerPlugin is meant to provide an extensible, user-customizable notification system that can be used to completely replace Trac's default notifications. At the very least, it will allow users to receive notices about attachments, and to opt-out from receiving messages due to the always_notify_(owner|reporter|updater) options. The full system (in the not-too-distant-future) will allow users to 'subscribe' to certain events by specifying simple yet powerful rules, such as asking to receive an announcement for any change that involves a ticket with a priority greater then 'high'. Later, a 'watch' feature is intended to replace CC usage, and allow watching of wiki-pages, and then to enable other plug-ins to provide new means for registering messages that users can subscribe to. The AnnouncerPlugin is meant to be agnostic to what is being watched; where you should send something (email, IRC, jabber, ...), and what format it should look at. All in good time. I've gone over the various tickets on t.e.o related to notification, and have summarized them at AnnouncerPlugin/Concerns for reference to keep in mind while developing the system. === Design === Users won't be interested in this; but developers might-- skip if you just want to use the plugin :) Announcer is not meant to just scratch a particular itch of wanting to hear about a certain kind of thing, or have a message be sent in a certain format. It's meant to be a comprehensive and extensible notification architecture that will allow far greater control of notification delivery to users, and also make it very easy for developers (me, you, anyone!) to modify how it works. Announcer is itself a plug-in, but it will be able to be enhanced by other plug-ins should anyone want to. As such it has a number of places where its existing behavior can be added to: * Producers: These initiate an event; the core Announcer producers are almost all implementations of I*ChangeListener interfaces, such as ITicketChangeListener, IAttachmentChangeListener, and IWikiChangeListener. When they receive events across these various interfaces, they package them into an event and (in particular) classify each event as a "realm" and "category". For example, "ticket, created", "ticket, changed", "ticket, deleted", "ticket, attachment added", etc. * Subscribers: These are responsible for discovering who is interested about hearing an event. Every subscriber registers itself as willing to handle subscriptions for a particular realm and/or category, and from there it checks to see what users may be interested in an event. The subscriber returns the user who is interested about the event and what method they're interested in hearing about it via-- e.g., email, IRC, IM, or whatever. * Formatters: Once it has been decided that this particular user is interested in hearing about this event, a formatter is invoked to transform that event into an actual message. Plain text, HTML, oneliner, are all example formatters. If someone would like the ticket change email to always display certain key properties even if not changed, all that's needed is a new formatter to accomplish that. * Distributors: Finally, the Distributor is the component that actually -sends- the message. Each one generally transmits via one type of communication channel; email, IRC, AIM, and suchlike. * Resolvers: The purpose of a resolver is to turn a username into an address. For certain corporate sites, a component to simply append "@example.com" to the authenticated trac username will be sufficient. The default resolver will simply use whatever email address the authenticated person has set in trac. Others may be more complicated and query an external resource to determine where to send "fubarbaz"'s emails. * Preferences: Various components may change their behavior based on user-preferences; does the user prefer HTML or plain-text? does the user not want to get messages when they update tickets? Etc. As each of these components is optional, and others may add new ones at a whim, how to manage the preferences was something of a problem. Each component could add its own preference panel, but that would litter up the interface a lot. Instead, Announcer provides its own preference interface that behaves the same way as IPreferencePanelProvider, except instead of providing an entire panel, it provides only a single "box". All the boxes are rendered together. == Status == This code is ALPHA at present, and NOT suitable for general use. I'll post it up when its basically working with an initial state; the goal for that point is backwards-compatibility to Trac notifications. Specifically, done: '''Producers''':: !TicketChangeProducer, !AttachmentChangeProducer. These both plug into the respective I*!ChangeListener's, and so any change to a ticket-- including adding/removing attachments-- are converted into announcement events and sent through. Notably, attachments on wiki pages aren't yet but just because talking about changes to attachments without their parent wiki would be silly. !WikiChangeProducer is top of the list once I start receiving emails from the system :) '''Subscribers''':: !StaticTicketSubscriber adds a static subscription to every event; its essentially identical to smtp_always_bcc. !LegacyTicketSubscriber mimics the behavior of always_notify_(owner|reporter|updater) but allows users to opt-out of these decisions. !CarbonCopySubscriber mimics the CC field behavior. !RuleBasedTicketSubscriber to do simple filtering on ticket events is about half done. '''Distributors''':: !EmailDistributor is basically done-- what with liberal theft from trac.notifications meaning I didn't have to re-implement the actual /sending/. :) Eventually I'm going to make it launch an external process (without waiting) I think -- as an option. I don't want a blocking SMTP going bad screwing up Trac. '''Resolvers''':: Subscriptions can provide either a name, or an address; in the case of an address (such as !StaticTicketSubscriber) its just sent. In the case of a name though, an address has to be obtained. !SessionEmailResolver grabs the email address associated with a session. !DefaultEmailResolver appends a set domain name on the end of the user name that's specified in trac.ini (The theory is that if you are hooking your Trac up to a corporate authentication, and your username is the same as your email, this can turn 'shansen' into 'shansen@example.org'). !SpecifiedEmailResoler allows a user to (in preferences) specifically choose an alternate email address (separate from the one obtained anywhere else) that they'd like to send to. * It's worth noting, ''which'' resolvers that are used are set in a trac.ini option and in order. So for my sit I'd set it to !SpecifiedEmailResolver, !SessionEmailResolver. So the email address used is the one specified in the session-- unless someone picks a different one. And yes I know they can change their main address, I do have a situation where it is undesirable to random notices to the main trac address but still desirable for said address to remain. == Bugs/Feature Requests == Existing bugs and feature requests for AnnouncerPlugin are [report:9?COMPONENT=AnnouncerPlugin here]. If you have any issues, create a [http://trac-hacks.org/newticket?component=AnnouncerPlugin&owner=ixokai new ticket]. == Download == Download the zipped source from [download:announcerplugin here]. '''Note''': Announcer isn't quite available yet-- re-factoring a bit then I'll post the alpha version up. == Source == You can check out AnnouncerPlugin from [http://trac-hacks.org/svn/announcerplugin here] using Subversion, or [source:announcerplugin browse the source] with Trac. '''Note''': Announcer isn't quite available yet-- re-factoring a bit then I'll post the alpha version up. == Example == Initially(very soon now), it'll simply be a drop-in replacement for the default notifications, extending them to include attachment additions and deletions, and allowing users to opt-out from receiving notices normally sent because of the always_notify_* options. == Recent Changes == [[ChangeLog(announcerplugin, 3)]] == Author/Contributors == '''Author:''' [wiki:ixokai] [[BR]] '''Contributors:'''