Package bodhi :: Module mail
[hide private]
[frames] | no frames]

Source Code for Module bodhi.mail

  1  # $Id: mail.py,v 1.4 2007/01/08 06:07:07 lmacken Exp $ 
  2  # This program is free software; you can redistribute it and/or modify 
  3  # it under the terms of the GNU General Public License as published by 
  4  # the Free Software Foundation; version 2 of the License. 
  5  # 
  6  # This program is distributed in the hope that it will be useful, 
  7  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  # GNU Library General Public License for more details. 
 10  # 
 11  # You should have received a copy of the GNU General Public License 
 12  # along with this program; if not, write to the Free Software 
 13  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 14   
 15  import rpm 
 16  import koji 
 17  import logging 
 18  import turbomail 
 19   
 20  from os.path import join 
 21  from turbomail import MailNotEnabledException 
 22  from turbogears import config, identity 
 23   
 24  from bodhi.util import sha1sum, rpm_fileheader 
 25  from bodhi.exceptions import RPMNotFound 
 26   
 27  log = logging.getLogger(__name__) 
 28   
 29  ## 
 30  ## All of the email messages that bodhi is going to be sending around, not 
 31  ## including the update notifications. 
 32  ## 
 33  ## Right now this is a bit scary; the 'fields' field represents all of the  
 34  ## update fields in the body of the message that need to be expanded. 
 35  ## 
 36  ## TODO: we might want to think about pulling this stuff out into a separate 
 37  ## configuration file (using ConfigObj?) 
 38  ## 
 39  messages = { 
 40   
 41      'new' : { 
 42          'body'    : """\ 
 43  %(email)s has submitted a new update for %(release)s\n\n%(updatestr)s 
 44  """, 
 45          'fields'  : lambda x: { 
 46                          'email'     : identity.current.user_name, 
 47                          'release'   : x.release.long_name, 
 48                          'updatestr' : str(x) 
 49                      } 
 50          }, 
 51   
 52      'deleted' : { 
 53          'body'    : """\ 
 54  %(email)s has deleted the %(package)s update for %(release)s\n\n%(updatestr)s 
 55  """, 
 56          'fields'  : lambda x: { 
 57                          'package'   : x.title, 
 58                          'email'     : identity.current.user_name, 
 59                          'release'   : '%s %s' % (x.release.long_name, x.status), 
 60                          'updatestr' : str(x) 
 61                      } 
 62          }, 
 63   
 64      'edited' : { 
 65          'body'    : """\ 
 66  %(email)s has edited the %(package)s update for %(release)s\n\n%(updatestr)s 
 67  """, 
 68          'fields'  : lambda x: { 
 69                          'package'   : x.title, 
 70                          'email'     : identity.current.user_name, 
 71                          'release'   : '%s %s' % (x.release.long_name, x.status), 
 72                          'updatestr' : str(x) 
 73                      } 
 74          }, 
 75   
 76      'pushed' : { 
 77          'body'    : """\ 
 78  %(package)s has been successfully pushed for %(release)s.\n\n%(updatestr)s 
 79  """, 
 80          'fields'  : lambda x: { 
 81                          'package'   : x.title, 
 82                          'release'   : '%s %s' % (x.release.long_name, x.status), 
 83                          'updatestr' : str(x) 
 84                      } 
 85      }, 
 86   
 87      'push' : { 
 88          'body'    : """\ 
 89  %(submitter)s has requested the pushing of the following update:\n\n%(updatestr)s 
 90  """, 
 91          'fields'  : lambda x: { 
 92                          'submitter' : identity.current.user_name, 
 93                          'updatestr' : str(x) 
 94                      } 
 95      }, 
 96   
 97      'unpush' : { 
 98          'body'    : """\ 
 99  %(submitter)s has requested the unpushing of the following update:\n\n%(updatestr)s 
100  """, 
101          'fields'  : lambda x: { 
102                          'submitter' : identity.current.user_name, 
103                          'updatestr' : str(x) 
104                      } 
105      }, 
106   
107      'unpushed' : { 
108          'body'    : """\ 
109  The following update has been unpushed\n\n%(updatestr)s 
110  """, 
111          'fields'  : lambda x: { 
112                          'updatestr' : str(x) 
113                      } 
114      }, 
115   
116      'revoke' : { 
117          'body'    : """\ 
118  %(submitter)s has revoked the request of the following update:\n\n%(updatestr)s 
119  """, 
120          'fields'  : lambda x: { 
121                          'submitter' : identity.current.user_name, 
122                          'updatestr' : str(x) 
123                      } 
124          }, 
125   
126      'move' : { 
127          'body'    : """\ 
128  %(submitter)s has requested the moving of the following update from Testing to Stable:\n\n%(updatestr)s 
129  """, 
130          'fields'  : lambda x: { 
131                          'submitter' : identity.current.user_name, 
132                          'updatestr' : str(x) 
133                      } 
134      }, 
135   
136      'moved' : { 
137          'body'    : """\ 
138  The following update has been moved from Testing to Stable:\n\n%(updatestr)s 
139  """, 
140          'fields'  : lambda x: { 
141                          'updatestr' : str(x) 
142                      } 
143      }, 
144   
145      'stablekarma' : { 
146          'body'    : """\ 
147  The following update has reached a karma of %(karma)d and is being automatically 
148  marked as stable.\n\n%(updatestr)s 
149  """, 
150          'fields'  : lambda x: { 
151                          'karma'     : x.karma, 
152                          'updatestr' : str(x)  
153                      } 
154      }, 
155   
156      'comment' : { 
157          'body'    : """\ 
158  The following comment has been added to the %(package)s update: 
159   
160  %(comment)s 
161   
162  To reply to this comment, please visit the URL at the bottom of this mail 
163   
164  %(updatestr)s 
165  """, 
166          'fields' : lambda x: { 
167                          'package'   : x.title, 
168                          'comment'   : x.comments[-1], 
169                          'updatestr' : str(x) 
170                     } 
171      }, 
172   
173      'old_testing' : { 
174          'body'    : """\ 
175  The update for %(package)s has been in 'testing' status for over 2 weeks. 
176  This update can be marked as stable after it achieves a karma of %(stablekarma)d 
177  or by clicking 'Push to Stable'. 
178   
179  This is just a courtesy nagmail.  Updates may reside in the testing repository 
180  for more than 2 weeks if you deem it necessary. 
181   
182  You can submit this update to be pushed to the stable repository by going to 
183  the following URL: 
184   
185      http://admin.fedoraproject.org/updates/move/%(package)s 
186   
187  %(updatestr)s 
188  """, 
189          'fields' : lambda x: { 
190                          'package'     : x.title, 
191                          'stablekarma' : config.get('stable_karma', 3), 
192                          'updatestr'   : str(x) 
193                     } 
194      } 
195   
196  } 
197   
198  errata_template = """\ 
199  -------------------------------------------------------------------------------- 
200  Fedora%(testing)s Update Notification 
201  %(update_id)s 
202  %(date)s 
203  -------------------------------------------------------------------------------- 
204   
205  Name        : %(name)s 
206  Product     : %(product)s 
207  Version     : %(version)s 
208  Release     : %(release)s 
209  URL         : %(url)s 
210  Summary     : %(summary)s 
211  Description : 
212  %(description)s 
213   
214  -------------------------------------------------------------------------------- 
215  %(notes)s%(changelog)s%(references)sUpdated packages: 
216   
217  %(filelist)s 
218   
219  This update can be installed with the "yum" update program.  Use  
220  su -c 'yum%(yum_repository)s update %(name)s'  
221  at the command line.  For more information, refer to "Managing Software 
222  with yum", available at http://docs.fedoraproject.org/yum/. 
223  -------------------------------------------------------------------------------- 
224  """ 
225   
226 -def get_template(update):
227 from bodhi.buildsys import get_session 228 line = str('-' * 80) + '\n' 229 templates = [] 230 koji_session = get_session() 231 232 for build in update.builds: 233 h = build.get_rpm_header() 234 info = {} 235 info['date'] = str(update.date_pushed) 236 info['name'] = h[rpm.RPMTAG_NAME] 237 info['summary'] = h[rpm.RPMTAG_SUMMARY] 238 info['version'] = h[rpm.RPMTAG_VERSION] 239 info['release'] = h[rpm.RPMTAG_RELEASE] 240 info['url'] = h[rpm.RPMTAG_URL] 241 if update.status == 'testing': 242 info['testing'] = ' Test' 243 info['yum_repository'] = ' --enablerepo=updates-testing' 244 else: 245 info['testing'] = '' 246 info['yum_repository'] = '' 247 248 info['subject'] = "%s%s%s Update: %s" % ( 249 update.type == 'security' and '[SECURITY] ' or '', 250 update.release.long_name, info['testing'], build.nvr) 251 info['update_id'] = update.update_id 252 info['description'] = h[rpm.RPMTAG_DESCRIPTION] 253 #info['updatepath'] = update.get_repo() 254 info['product'] = update.release.long_name 255 info['notes'] = "" 256 if update.notes and len(update.notes): 257 info['notes'] = "Update Information:\n\n%s\n" % update.notes 258 info['notes'] += line 259 260 # Build the list of SHA1SUMs and packages 261 filelist = [] 262 for pkg in koji_session.listBuildRPMs(build.nvr): 263 filename = "%s.%s.rpm" % (pkg['nvr'], pkg['arch']) 264 path = join(config.get('build_dir'), info['name'], info['version'], 265 info['release'], pkg['arch']) 266 filelist.append("%s %s" % (sha1sum(join(path, filename)), filename)) 267 info['filelist'] = '\n'.join(filelist) 268 269 # Add this updates referenced Bugzillas and CVEs 270 i = 1 271 info['references'] = "" 272 if len(update.bugs) or len(update.cves): 273 info['references'] = "References:\n\n" 274 for bug in update.bugs: 275 title = (bug.title != 'Unable to fetch title' and 276 bug.title != 'Invalid bug number') and \ 277 ' - %s' % bug.title or '' 278 info['references'] += " [ %d ] Bug #%d%s\n %s\n" % \ 279 (i, bug.bz_id, title, bug.get_url()) 280 i += 1 281 for cve in update.cves: 282 info['references'] += " [ %d ] %s\n %s\n" % \ 283 (i, cve.cve_id, cve.get_url()) 284 i += 1 285 info['references'] += line 286 287 # Find the most recent update for this package, other than this one 288 lastpkg = build.get_latest() 289 log.debug("lastpkg = %s" % lastpkg) 290 291 # Grab the RPM header of the previous update, and generate a ChangeLog 292 info['changelog'] = "" 293 try: 294 oldh = rpm_fileheader(lastpkg) 295 oldtime = oldh[rpm.RPMTAG_CHANGELOGTIME] 296 text = oldh[rpm.RPMTAG_CHANGELOGTEXT] 297 del oldh 298 if not text: 299 oldtime = 0 300 elif len(text) != 1: 301 oldtime = oldtime[0] 302 info['changelog'] = "ChangeLog:\n\n%s%s" % \ 303 (str(build.get_changelog(oldtime)), line) 304 except RPMNotFound: 305 log.error("Cannot find 'latest' RPM for generating ChangeLog: %s" % 306 lastpkg) 307 except Exception, e: 308 log.error("Unknown exception thrown during ChangeLog generation: %s" 309 % str(e)) 310 311 for (key, value) in info.items(): 312 if value: 313 info[key] = value.decode('utf8') 314 315 templates.append((info['subject'], errata_template % info)) 316 317 return templates
318
319 -def send_mail(sender, to, subject, body):
320 message = turbomail.Message(sender, to, subject) 321 message.plain = body 322 try: 323 turbomail.enqueue(message) 324 log.debug("Sending mail: %s" % message.plain) 325 except MailNotEnabledException: 326 log.warning("TurboMail is not enabled!") 327 except Exception, e: 328 log.error("Exception thrown when trying to send mail: %s" % str(e))
329
330 -def send(to, msg_type, update, sender=None):
331 """ Send an update notification email to a given recipient """ 332 if not sender: 333 sender = config.get('bodhi_email') 334 if not sender: 335 log.warning("bodhi_email not defined in app.cfg; unable to send mail") 336 return 337 send_mail(sender, to, '[Fedora Update] [%s] %s' % (msg_type, update.title), 338 messages[msg_type]['body'] % messages[msg_type]['fields'](update))
339
340 -def send_releng(subject, body):
341 """ Send the Release Engineering team a message """ 342 send_mail(config.get('bodhi_email'), config.get('release_team_address'), 343 subject, body)
344
345 -def send_admin(msg_type, update, sender=None):
346 """ Send an update notification to the admins/release team. """ 347 send(config.get('release_team_address'), msg_type, update, sender)
348