Ticket #3514: notification.py

File notification.py, 5.6 kB (added by van.frag, 2 months ago)
Line 
1 """
2 License: BSD
3
4  van.frag (van.frag@gmail.com)
5 """
6 import re
7 import md5
8
9 from trac import __version__
10 from trac.core import *
11 from trac.util.text import CRLF
12 from trac.wiki.model import WikiPage
13 from trac.versioncontrol.diff import unified_diff
14 from trac.notification import NotifyEmail
15 from trac.config import Option, BoolOption, ListOption, IntOption
16 from tracfullblog.model import BlogPost, BlogComment
17
18 from genshi.template.text import TextTemplate
19
20
21 class BlogNotifierEmail(NotifyEmail):
22     template_name = "blog_notifier_email_template.txt"
23     from_email = 'trac+wiki@localhost'
24     blocked_addresses = []
25
26     def __init__(self, env):
27         NotifyEmail.__init__(self, env)
28
29         self.from_name = self.config.get('blog-notifier', 'from_name')
30         self.banned_addresses = []
31
32     def notify(self, bp, action,
33                version=None,
34                time=None,
35                comment=None,
36                author=None):
37         self.bp = bp
38         self.change_author = author
39         self.time = time
40         self.action = action
41         self.version = version
42
43         self.data['name']= bp.name
44         self.data['title']= bp.title
45         self.data['body']= bp.body
46         self.data['comment']= comment
47         self.data['version']= version
48         self.data['author']= author
49         self.data['action']= action
50         self.data['time'] = time
51         self.data['link']= self.env.abs_href.blog(bp.name)
52        
53         subject = self.format_subject(action.replace('_', ' '))
54
55         NotifyEmail.notify(self, bp.name, subject)
56
57     def get_recipients(self, pagename):
58        
59         tos = self.config.getlist("blog-notifier","smtp_always_bcc")
60        
61         self.env.log.debug("TO's TO NOTIFY: %s", tos)
62         return (tos, [])
63
64     def send(self, torcpts, ccrcpts, mime_headers={}):
65         from email.MIMEText import MIMEText
66         from email.Utils import formatdate
67
68         stream = self.template.generate(**self.data)
69         body = stream.render('text')
70         projname = self.config.get('project', 'name')
71         headers = {}
72         headers['X-Mailer'] = 'Trac %s, by Edgewall Software' % __version__
73         headers['X-Trac-Version'] =  __version__
74         headers['X-Trac-Project'] =  projname
75         headers['X-URL'] = self.config.get('project', 'url')
76         headers['Precedence'] = 'bulk'
77         headers['Auto-Submitted'] = 'auto-generated'
78         headers['Subject'] = self.subject
79         headers['From'] = (self.from_name or projname, self.from_email)
80         headers['Reply-To'] = self.replyto_email
81
82         def build_addresses(rcpts):
83             """Format and remove invalid addresses"""
84             return filter(lambda x: x, \
85                           [self.get_smtp_address(addr) for addr in rcpts])
86
87         def remove_dup(rcpts, all):
88             """Remove duplicates"""
89             tmp = []
90             for rcpt in rcpts:
91                 if rcpt in self.banned_addresses:
92                     self.env.log.debug("Banned Address: %s", rcpt)
93                     self.blocked_addresses.append(rcpt)
94                 elif not rcpt in all:
95                     tmp.append(rcpt)
96                     all.append(rcpt)
97             return (tmp, all)
98
99         toaddrs = build_addresses(torcpts)
100         ccaddrs = build_addresses(ccrcpts)
101         accaddrs = []
102         bccparam = self.config.getlist('blog-notifier', 'smtp_always_bcc')
103         bccaddrs = bccparam and build_addresses(bccparam) or []
104
105         recipients = []
106         (toaddrs, recipients) = remove_dup(toaddrs, recipients)
107         (ccaddrs, recipients) = remove_dup(ccaddrs, recipients)
108         (accaddrs, recipients) = remove_dup(accaddrs, recipients)
109         (bccaddrs, recipients) = remove_dup(bccaddrs, recipients)
110
111         self.env.log.debug("Not notifying the following addresses: %s",
112                            ', '.join(self.blocked_addresses))
113
114         # if there is not valid recipient, leave immediately
115         if len(recipients) < 1:
116             self.env.log.info('no recipient for a wiki notification')
117             return
118
119         dest = self.change_author or 'anonymous'
120         headers['X-Trac-Wiki-URL'] = self.data['link']
121
122         pcc = accaddrs
123         if pcc:
124             headers['Cc'] = ', '.join(pcc)
125         headers['Date'] = formatdate()
126         # sanity check
127         if not self._charset.body_encoding:
128             try:
129                 dummy = body.encode('ascii')
130             except UnicodeDecodeError:
131                 raise TracError(_("WikiPage contains non-Ascii chars. " \
132                                   "Please change encoding setting"))
133
134         msg = MIMEText(body, 'plain')
135         # Message class computes the wrong type from MIMEText constructor,
136         # which does not take a Charset object as initializer. Reset the
137         # encoding type to force a new, valid evaluation
138         del msg['Content-Transfer-Encoding']
139         msg.set_charset(self._charset)
140
141         self.add_headers(msg, headers);
142         self.add_headers(msg, mime_headers);
143         self.env.log.info("Sending SMTP notification to %s:%d to %s"
144                            % (self.smtp_server, self.smtp_port, recipients))
145         msgtext = msg.as_string()
146         # Ensure the message complies with RFC2822: use CRLF line endings
147         recrlf = re.compile("\r?\n")
148         msgtext = CRLF.join(recrlf.split(msgtext))
149         try:
150             self.server.sendmail(msg['From'], recipients, msgtext)
151         except Exception, err:
152             self.env.log.debug('Notification could not be sent: %r', err)
153
154     def format_subject(self, action):
155
156         prefix = '[%s]' % self.config.get('project', 'name')
157
158         prefix = prefix + ' Blog ' + self.bp.title
159        
160         return prefix.strip()