Merge lp:~cjwatson/launchpad/message-for-header into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 17730
Proposed branch: lp:~cjwatson/launchpad/message-for-header
Merge into: lp:launchpad
Diff against target: 895 lines (+141/-40)
28 files modified
lib/lp/answers/model/questionjob.py (+1/-0)
lib/lp/bugs/doc/bugnotification-email.txt (+6/-0)
lib/lp/bugs/doc/bugnotification-sending.txt (+30/-4)
lib/lp/bugs/doc/initial-bug-contacts.txt (+2/-0)
lib/lp/bugs/mail/bugnotificationbuilder.py (+11/-0)
lib/lp/bugs/stories/bugs/bug-add-subscriber.txt (+1/-0)
lib/lp/code/doc/branch-merge-proposal-notifications.txt (+12/-7)
lib/lp/code/doc/branch-notifications.txt (+2/-0)
lib/lp/code/doc/codeimport.txt (+2/-0)
lib/lp/code/mail/codeimport.py (+5/-1)
lib/lp/code/mail/tests/test_branch.py (+2/-0)
lib/lp/code/mail/tests/test_branchmergeproposal.py (+1/-0)
lib/lp/code/mail/tests/test_codereviewcomment.py (+2/-0)
lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py (+4/-0)
lib/lp/registry/browser/person.py (+1/-1)
lib/lp/registry/doc/teammembership-email-notification.txt (+2/-1)
lib/lp/registry/mail/notification.py (+7/-4)
lib/lp/registry/model/productjob.py (+2/-1)
lib/lp/registry/tests/test_notification.py (+10/-6)
lib/lp/registry/tests/test_productjob.py (+3/-1)
lib/lp/services/mail/basemailer.py (+2/-0)
lib/lp/services/mail/notificationrecipientset.py (+1/-0)
lib/lp/services/mail/tests/test_basemailer.py (+3/-1)
lib/lp/snappy/tests/test_snapbuild.py (+1/-0)
lib/lp/soyuz/mail/tests/test_packageupload.py (+14/-7)
lib/lp/soyuz/tests/test_build_notify.py (+3/-0)
lib/lp/soyuz/tests/test_livefsbuild.py (+2/-1)
lib/lp/testing/mail_helpers.py (+9/-5)
To merge this branch: bzr merge lp:~cjwatson/launchpad/message-for-header
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+270811@code.launchpad.net

Commit message

Add an X-Launchpad-Message-For header with just the name of the person subscribed to the notification.

Description of the change

Add an X-Launchpad-Message-For header with just the name of the person subscribed to the notification.

There are several times more implementations of this than there ought to be, because not everything goes through BaseMailer yet; and the implementation for bug notifications is horrible because BugNotificationRecipient doesn't (I think) provide enough information.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/answers/model/questionjob.py'
--- lib/lp/answers/model/questionjob.py 2015-08-25 16:24:06 +0000
+++ lib/lp/answers/model/questionjob.py 2015-09-11 12:44:20 +0000
@@ -236,6 +236,7 @@
236 for email in recipients.getEmails():236 for email in recipients.getEmails():
237 reason, header = recipients.getReason(email)237 reason, header = recipients.getReason(email)
238 headers['X-Launchpad-Message-Rationale'] = header238 headers['X-Launchpad-Message-Rationale'] = header
239 headers['X-Launchpad-Message-For'] = reason.subscriber.name
239 formatted_body = self.buildBody(reason.getReason())240 formatted_body = self.buildBody(reason.getReason())
240 simple_sendmail(241 simple_sendmail(
241 self.from_address, email, self.subject, formatted_body,242 self.from_address, email, self.subject, formatted_body,
242243
=== modified file 'lib/lp/bugs/doc/bugnotification-email.txt'
--- lib/lp/bugs/doc/bugnotification-email.txt 2015-07-31 14:46:31 +0000
+++ lib/lp/bugs/doc/bugnotification-email.txt 2015-09-11 12:44:20 +0000
@@ -585,6 +585,12 @@
585 >>> print notification_email['X-Launchpad-Message-Rationale']585 >>> print notification_email['X-Launchpad-Message-Rationale']
586 Because-I-said-so586 Because-I-said-so
587587
588The X-Launchpad-Message-For header is set from the to_person (since this
589notification is not for a team).
590
591 >>> print notification_email['X-Launchpad-Message-For']
592 name16
593
588The references parameter sets the References header of the email.594The references parameter sets the References header of the email.
589595
590 >>> print notification_email['References']596 >>> print notification_email['References']
591597
=== modified file 'lib/lp/bugs/doc/bugnotification-sending.txt'
--- lib/lp/bugs/doc/bugnotification-sending.txt 2015-07-13 16:14:46 +0000
+++ lib/lp/bugs/doc/bugnotification-sending.txt 2015-09-11 12:44:20 +0000
@@ -22,6 +22,7 @@
22 >>> def print_notification_headers(email_notification, extra_headers=[]):22 >>> def print_notification_headers(email_notification, extra_headers=[]):
23 ... for header in ['To', 'From', 'Subject',23 ... for header in ['To', 'From', 'Subject',
24 ... 'X-Launchpad-Message-Rationale',24 ... 'X-Launchpad-Message-Rationale',
25 ... 'X-Launchpad-Message-For',
25 ... 'X-Launchpad-Subscription'] + extra_headers:26 ... 'X-Launchpad-Subscription'] + extra_headers:
26 ... if email_notification[header]:27 ... if email_notification[header]:
27 ... print "%s: %s" % (header, email_notification[header])28 ... print "%s: %s" % (header, email_notification[header])
@@ -73,6 +74,7 @@
73 From: Sample Person <1@bugs.launchpad.net>74 From: Sample Person <1@bugs.launchpad.net>
74 Subject: [Bug 1] subject75 Subject: [Bug 1] subject
75 X-Launchpad-Message-Rationale: Subscriber (mozilla-firefox in Ubuntu)76 X-Launchpad-Message-Rationale: Subscriber (mozilla-firefox in Ubuntu)
77 X-Launchpad-Message-For: name16
76 <BLANKLINE>78 <BLANKLINE>
77 a comment.79 a comment.
78 <BLANKLINE>80 <BLANKLINE>
@@ -82,6 +84,7 @@
82 From: Sample Person <1@bugs.launchpad.net>84 From: Sample Person <1@bugs.launchpad.net>
83 Subject: [Bug 1] subject85 Subject: [Bug 1] subject
84 X-Launchpad-Message-Rationale: Assignee86 X-Launchpad-Message-Rationale: Assignee
87 X-Launchpad-Message-For: mark
85 <BLANKLINE>88 <BLANKLINE>
86 a comment.89 a comment.
87 <BLANKLINE>90 <BLANKLINE>
@@ -91,6 +94,7 @@
91 From: Sample Person <1@bugs.launchpad.net>94 From: Sample Person <1@bugs.launchpad.net>
92 Subject: [Bug 1] subject95 Subject: [Bug 1] subject
93 X-Launchpad-Message-Rationale: Subscriber96 X-Launchpad-Message-Rationale: Subscriber
97 X-Launchpad-Message-For: name12
94 <BLANKLINE>98 <BLANKLINE>
95 a comment.99 a comment.
96 <BLANKLINE>100 <BLANKLINE>
@@ -154,6 +158,7 @@
154 From: Sample Person <1@bugs.launchpad.net>158 From: Sample Person <1@bugs.launchpad.net>
155 Subject: Re: [Bug 1] subject159 Subject: Re: [Bug 1] subject
156 X-Launchpad-Message-Rationale: Assignee160 X-Launchpad-Message-Rationale: Assignee
161 X-Launchpad-Message-For: mark
157 <BLANKLINE>162 <BLANKLINE>
158 a new comment.163 a new comment.
159 <BLANKLINE>164 <BLANKLINE>
@@ -193,6 +198,7 @@
193 From: Sample Person <1@bugs.launchpad.net>198 From: Sample Person <1@bugs.launchpad.net>
194 Subject: [Bug 1] Re: Firefox does not support SVG199 Subject: [Bug 1] Re: Firefox does not support SVG
195 X-Launchpad-Message-Rationale: Assignee200 X-Launchpad-Message-Rationale: Assignee
201 X-Launchpad-Message-For: mark
196 <BLANKLINE>202 <BLANKLINE>
197 ** Summary changed:203 ** Summary changed:
198 - Old summary204 - Old summary
@@ -239,6 +245,7 @@
239 From: Sample Person <1@bugs.launchpad.net>245 From: Sample Person <1@bugs.launchpad.net>
240 Subject: [Bug 1] Re: Firefox does not support SVG246 Subject: [Bug 1] Re: Firefox does not support SVG
241 X-Launchpad-Message-Rationale: Assignee247 X-Launchpad-Message-Rationale: Assignee
248 X-Launchpad-Message-For: mark
242 <BLANKLINE>249 <BLANKLINE>
243 a new comment.250 a new comment.
244 <BLANKLINE>251 <BLANKLINE>
@@ -366,6 +373,7 @@
366 From: Sample Person <16@bugs.launchpad.net>373 From: Sample Person <16@bugs.launchpad.net>
367 Subject: [Bug 16] [NEW] new bug374 Subject: [Bug 16] [NEW] new bug
368 X-Launchpad-Message-Rationale: Subscriber375 X-Launchpad-Message-Rationale: Subscriber
376 X-Launchpad-Message-For: name12
369 <BLANKLINE>377 <BLANKLINE>
370 Public bug reported:378 Public bug reported:
371 ...379 ...
@@ -396,6 +404,7 @@
396 From: Sample Person <16@bugs.launchpad.net>404 From: Sample Person <16@bugs.launchpad.net>
397 Subject: [Bug 16] subject405 Subject: [Bug 16] subject
398 X-Launchpad-Message-Rationale: Subscriber406 X-Launchpad-Message-Rationale: Subscriber
407 X-Launchpad-Message-For: name12
399 X-Launchpad-Bug-Duplicate: 1408 X-Launchpad-Bug-Duplicate: 1
400 <BLANKLINE>409 <BLANKLINE>
401 *** This bug is a duplicate of bug 1 ***410 *** This bug is a duplicate of bug 1 ***
@@ -432,6 +441,7 @@
432 From: Sample Person <...@bugs.launchpad.net>441 From: Sample Person <...@bugs.launchpad.net>
433 Subject: [Bug ...] [NEW] Zero-day on Frobulator442 Subject: [Bug ...] [NEW] Zero-day on Frobulator
434 X-Launchpad-Message-Rationale: Subscriber443 X-Launchpad-Message-Rationale: Subscriber
444 X-Launchpad-Message-For: name12
435 <BLANKLINE>445 <BLANKLINE>
436 *** This bug is a security vulnerability ***446 *** This bug is a security vulnerability ***
437 <BLANKLINE>447 <BLANKLINE>
@@ -456,6 +466,7 @@
456 From: Sample Person <...@bugs.launchpad.net>466 From: Sample Person <...@bugs.launchpad.net>
457 Subject: [Bug ...] subject467 Subject: [Bug ...] subject
458 X-Launchpad-Message-Rationale: Subscriber468 X-Launchpad-Message-Rationale: Subscriber
469 X-Launchpad-Message-For: name12
459 <BLANKLINE>470 <BLANKLINE>
460 a comment.471 a comment.
461 <BLANKLINE>472 <BLANKLINE>
@@ -538,6 +549,7 @@
538 References: foo@example.com-332342--1231549 References: foo@example.com-332342--1231
539 ...550 ...
540 X-Launchpad-Message-Rationale: Assignee551 X-Launchpad-Message-Rationale: Assignee
552 X-Launchpad-Message-For: name12
541 ...553 ...
542 INFO Notifying foo.bar@canonical.com about bug 1.554 INFO Notifying foo.bar@canonical.com about bug 1.
543 ...555 ...
@@ -548,6 +560,7 @@
548 References: sdsdfsfd560 References: sdsdfsfd
549 ...561 ...
550 X-Launchpad-Message-Rationale: Subscriber (mozilla-firefox in Ubuntu)562 X-Launchpad-Message-Rationale: Subscriber (mozilla-firefox in Ubuntu)
563 X-Launchpad-Message-For: name16
551 ...564 ...
552 INFO Notifying mark@example.com about bug 1.565 INFO Notifying mark@example.com about bug 1.
553 ...566 ...
@@ -564,6 +577,7 @@
564 References: sdsdfsfd577 References: sdsdfsfd
565 ...578 ...
566 X-Launchpad-Message-Rationale: Subscriber (mozilla-firefox in Ubuntu)579 X-Launchpad-Message-Rationale: Subscriber (mozilla-firefox in Ubuntu)
580 X-Launchpad-Message-For: name16
567 Errors-To: bounces@canonical.com581 Errors-To: bounces@canonical.com
568 Return-Path: bounces@canonical.com582 Return-Path: bounces@canonical.com
569 Precedence: bulk583 Precedence: bulk
@@ -840,12 +854,14 @@
840 ... "will be automatically wrapped by the BugNotification "854 ... "will be automatically wrapped by the BugNotification "
841 ... "machinery. Ain't technology great?")855 ... "machinery. Ain't technology great?")
842 ... verbose_person = factory.makePerson(856 ... verbose_person = factory.makePerson(
843 ... displayname='Verbose Person', email='verbose@example.com',857 ... name='verbose-person', displayname='Verbose Person',
858 ... email='verbose@example.com',
844 ... selfgenerated_bugnotifications=True)859 ... selfgenerated_bugnotifications=True)
845 ... verbose_person.verbose_bugnotifications = True860 ... verbose_person.verbose_bugnotifications = True
846 ... ignored = bug.subscribe(verbose_person, verbose_person)861 ... ignored = bug.subscribe(verbose_person, verbose_person)
847 ... concise_person = factory.makePerson(862 ... concise_person = factory.makePerson(
848 ... displayname='Concise Person', email='concise@example.com')863 ... name='concise-person', displayname='Concise Person',
864 ... email='concise@example.com')
849 ... concise_person.verbose_bugnotifications = False865 ... concise_person.verbose_bugnotifications = False
850 ... ignored = bug.subscribe(concise_person, concise_person)866 ... ignored = bug.subscribe(concise_person, concise_person)
851867
@@ -858,7 +874,7 @@
858 ... name='conciseteam', displayname='Concise Team')874 ... name='conciseteam', displayname='Concise Team')
859 ... concise_team.verbose_bugnotifications = False875 ... concise_team.verbose_bugnotifications = False
860 ... concise_team_person = factory.makePerson(876 ... concise_team_person = factory.makePerson(
861 ... displayname='Concise Team Person',877 ... name='conciseteam-person', displayname='Concise Team Person',
862 ... email='conciseteam@example.com')878 ... email='conciseteam@example.com')
863 ... concise_team_person.verbose_bugnotifications = True879 ... concise_team_person.verbose_bugnotifications = True
864 ... ignored = concise_team.addMember(880 ... ignored = concise_team.addMember(
@@ -873,7 +889,7 @@
873 ... name='verboseteam', displayname='Verbose Team')889 ... name='verboseteam', displayname='Verbose Team')
874 ... verbose_team.verbose_bugnotifications = True890 ... verbose_team.verbose_bugnotifications = True
875 ... verbose_team_person = factory.makePerson(891 ... verbose_team_person = factory.makePerson(
876 ... displayname='Verbose Team Person',892 ... name='verboseteam-person', displayname='Verbose Team Person',
877 ... email='verboseteam@example.com')893 ... email='verboseteam@example.com')
878 ... verbose_team_person.verbose_bugnotifications = False894 ... verbose_team_person.verbose_bugnotifications = False
879 ... ignored = verbose_team.addMember(895 ... ignored = verbose_team.addMember(
@@ -934,6 +950,7 @@
934 From: Verbose Person <verbose@example.com>950 From: Verbose Person <verbose@example.com>
935 Subject: [Bug ...] subject951 Subject: [Bug ...] subject
936 X-Launchpad-Message-Rationale: Subscriber952 X-Launchpad-Message-Rationale: Subscriber
953 X-Launchpad-Message-For: concise-person
937 <BLANKLINE>954 <BLANKLINE>
938 a really simple comment.955 a really simple comment.
939 <BLANKLINE>956 <BLANKLINE>
@@ -961,6 +978,7 @@
961 From: Verbose Person <verbose@example.com>978 From: Verbose Person <verbose@example.com>
962 Subject: [Bug ...] subject979 Subject: [Bug ...] subject
963 X-Launchpad-Message-Rationale: Subscriber @verboseteam980 X-Launchpad-Message-Rationale: Subscriber @verboseteam
981 X-Launchpad-Message-For: verboseteam
964 <BLANKLINE>982 <BLANKLINE>
965 a really simple comment.983 a really simple comment.
966 <BLANKLINE>984 <BLANKLINE>
@@ -980,6 +998,7 @@
980 From: Verbose Person <verbose@example.com>998 From: Verbose Person <verbose@example.com>
981 Subject: [Bug ...] subject999 Subject: [Bug ...] subject
982 X-Launchpad-Message-Rationale: Subscriber1000 X-Launchpad-Message-Rationale: Subscriber
1001 X-Launchpad-Message-For: verbose-person
983 <BLANKLINE>1002 <BLANKLINE>
984 a really simple comment.1003 a really simple comment.
985 <BLANKLINE>1004 <BLANKLINE>
@@ -1010,6 +1029,7 @@
1010 From: Verbose Person <verbose@example.com>1029 From: Verbose Person <verbose@example.com>
1011 Subject: [Bug ...] subject1030 Subject: [Bug ...] subject
1012 X-Launchpad-Message-Rationale: Subscriber @conciseteam1031 X-Launchpad-Message-Rationale: Subscriber @conciseteam
1032 X-Launchpad-Message-For: conciseteam
1013 <BLANKLINE>1033 <BLANKLINE>
1014 a really simple comment.1034 a really simple comment.
1015 <BLANKLINE>1035 <BLANKLINE>
@@ -1134,6 +1154,7 @@
1134 From: Sample Person <...@bugs.launchpad.net>1154 From: Sample Person <...@bugs.launchpad.net>
1135 Subject: [Bug 1] subject1155 Subject: [Bug 1] subject
1136 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)1156 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)
1157 X-Launchpad-Message-For: no-priv
1137 <BLANKLINE>1158 <BLANKLINE>
1138 another comment.1159 another comment.
1139 <BLANKLINE>1160 <BLANKLINE>
@@ -1190,6 +1211,7 @@
1190 From: Sample Person <...@bugs.launchpad.net>1211 From: Sample Person <...@bugs.launchpad.net>
1191 Subject: [Bug 1] subject1212 Subject: [Bug 1] subject
1192 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)1213 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)
1214 X-Launchpad-Message-For: no-priv
1193 X-Launchpad-Subscription: Allow-comments filter1215 X-Launchpad-Subscription: Allow-comments filter
1194 <BLANKLINE>1216 <BLANKLINE>
1195 another comment.1217 another comment.
@@ -1245,6 +1267,7 @@
1245 From: Sample Person <...@bugs.launchpad.net>1267 From: Sample Person <...@bugs.launchpad.net>
1246 Subject: [Bug 1] subject1268 Subject: [Bug 1] subject
1247 X-Launchpad-Message-Rationale: Subscriber @addressless1269 X-Launchpad-Message-Rationale: Subscriber @addressless
1270 X-Launchpad-Message-For: addressless
1248 <BLANKLINE>1271 <BLANKLINE>
1249 no comment for no-priv.1272 no comment for no-priv.
1250 <BLANKLINE>1273 <BLANKLINE>
@@ -1291,6 +1314,7 @@
1291 From: Sample Person <...@bugs.launchpad.net>1314 From: Sample Person <...@bugs.launchpad.net>
1292 Subject: [Bug 1] subject1315 Subject: [Bug 1] subject
1293 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)1316 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)
1317 X-Launchpad-Message-For: no-priv
1294 X-Launchpad-Subscription: Allow-comments filter1318 X-Launchpad-Subscription: Allow-comments filter
1295 <BLANKLINE>1319 <BLANKLINE>
1296 no comment for no-priv.1320 no comment for no-priv.
@@ -1350,6 +1374,7 @@
1350 From: Sample Person <...@bugs.launchpad.net>1374 From: Sample Person <...@bugs.launchpad.net>
1351 Subject: [Bug 1] Re: Firefox does not support SVG1375 Subject: [Bug 1] Re: Firefox does not support SVG
1352 X-Launchpad-Message-Rationale: Subscriber @addressless1376 X-Launchpad-Message-Rationale: Subscriber @addressless
1377 X-Launchpad-Message-For: addressless
1353 <BLANKLINE>1378 <BLANKLINE>
1354 ** Summary changed:1379 ** Summary changed:
1355 - Whatever1380 - Whatever
@@ -1405,6 +1430,7 @@
1405 From: Sample Person <...@bugs.launchpad.net>1430 From: Sample Person <...@bugs.launchpad.net>
1406 Subject: [Bug 1] Re: Firefox does not support SVG1431 Subject: [Bug 1] Re: Firefox does not support SVG
1407 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)1432 X-Launchpad-Message-Rationale: Subscriber (Mozilla Firefox)
1433 X-Launchpad-Message-For: no-priv
1408 <BLANKLINE>1434 <BLANKLINE>
1409 ** Summary changed:1435 ** Summary changed:
1410 - I'm losing my1436 - I'm losing my
14111437
=== modified file 'lib/lp/bugs/doc/initial-bug-contacts.txt'
--- lib/lp/bugs/doc/initial-bug-contacts.txt 2012-08-16 07:02:41 +0000
+++ lib/lp/bugs/doc/initial-bug-contacts.txt 2015-09-11 12:44:20 +0000
@@ -191,6 +191,8 @@
191191
192 >>> msg['X-Launchpad-Message-Rationale']192 >>> msg['X-Launchpad-Message-Rationale']
193 'Subscriber (pmount in Ubuntu)'193 'Subscriber (pmount in Ubuntu)'
194 >>> msg['X-Launchpad-Message-For']
195 'daf'
194196
195 >>> msg['Subject']197 >>> msg['Subject']
196 '[Bug 1] [NEW] Firefox does not support SVG'198 '[Bug 1] [NEW] Firefox does not support SVG'
197199
=== modified file 'lib/lp/bugs/mail/bugnotificationbuilder.py'
--- lib/lp/bugs/mail/bugnotificationbuilder.py 2015-08-28 06:44:52 +0000
+++ lib/lp/bugs/mail/bugnotificationbuilder.py 2015-09-11 12:44:20 +0000
@@ -13,6 +13,7 @@
1313
14from email.mime.text import MIMEText14from email.mime.text import MIMEText
15from email.utils import formatdate15from email.utils import formatdate
16import re
16import rfc82217import rfc822
1718
18from zope.component import getUtility19from zope.component import getUtility
@@ -207,6 +208,16 @@
207208
208 if rationale is not None:209 if rationale is not None:
209 headers.append(('X-Launchpad-Message-Rationale', rationale))210 headers.append(('X-Launchpad-Message-Rationale', rationale))
211 # XXX cjwatson 2015-09-11: The ridiculously complicated way that
212 # bug notifications are built means that we no longer have
213 # direct access to the subscriber name at this point. As a
214 # stopgap, parse it out of the rationale.
215 match = re.search(r'@([^ ]*)', rationale)
216 if match is not None:
217 message_for = match.group(1)
218 else:
219 message_for = removeSecurityProxy(to_person).name
220 headers.append(('X-Launchpad-Message-For', message_for))
210221
211 if filters is not None:222 if filters is not None:
212 for filter in filters:223 for filter in filters:
213224
=== modified file 'lib/lp/bugs/stories/bugs/bug-add-subscriber.txt'
--- lib/lp/bugs/stories/bugs/bug-add-subscriber.txt 2012-07-27 01:15:04 +0000
+++ lib/lp/bugs/stories/bugs/bug-add-subscriber.txt 2015-09-11 12:44:20 +0000
@@ -82,6 +82,7 @@
82 Reply-To: Bug ... <...@bugs.launchpad.net>82 Reply-To: Bug ... <...@bugs.launchpad.net>
83 ...83 ...
84 X-Launchpad-Message-Rationale: Subscriber84 X-Launchpad-Message-Rationale: Subscriber
85 X-Launchpad-Message-For: ddaa
85 ...86 ...
86 You have been subscribed to a public bug by No Privileges Person (no-priv):87 You have been subscribed to a public bug by No Privileges Person (no-priv):
87 ...88 ...
8889
=== modified file 'lib/lp/code/doc/branch-merge-proposal-notifications.txt'
--- lib/lp/code/doc/branch-merge-proposal-notifications.txt 2015-09-02 16:54:24 +0000
+++ lib/lp/code/doc/branch-merge-proposal-notifications.txt 2015-09-11 12:44:20 +0000
@@ -29,13 +29,15 @@
29 >>> previewdiff = factory.makePreviewDiff(merge_proposal=bmp)29 >>> previewdiff = factory.makePreviewDiff(merge_proposal=bmp)
30 >>> transaction.commit()30 >>> transaction.commit()
31 >>> source_subscriber = factory.makePerson(31 >>> source_subscriber = factory.makePerson(
32 ... email='source@example.com', displayname='Source Subscriber')32 ... email='source@example.com', name='source-subscriber',
33 ... displayname='Source Subscriber')
33 >>> _unused = bmp.source_branch.subscribe(source_subscriber,34 >>> _unused = bmp.source_branch.subscribe(source_subscriber,
34 ... BranchSubscriptionNotificationLevel.NOEMAIL,35 ... BranchSubscriptionNotificationLevel.NOEMAIL,
35 ... BranchSubscriptionDiffSize.NODIFF,36 ... BranchSubscriptionDiffSize.NODIFF,
36 ... CodeReviewNotificationLevel.STATUS, source_subscriber)37 ... CodeReviewNotificationLevel.STATUS, source_subscriber)
37 >>> target_subscriber = factory.makePerson(38 >>> target_subscriber = factory.makePerson(
38 ... email='target@example.com', displayname='Target Subscriber')39 ... email='target@example.com', name='target-subscriber',
40 ... displayname='Target Subscriber')
39 >>> target_subscription = bmp.target_branch.subscribe(target_subscriber,41 >>> target_subscription = bmp.target_branch.subscribe(target_subscriber,
40 ... BranchSubscriptionNotificationLevel.NOEMAIL,42 ... BranchSubscriptionNotificationLevel.NOEMAIL,
41 ... BranchSubscriptionDiffSize.NODIFF,43 ... BranchSubscriptionDiffSize.NODIFF,
@@ -136,6 +138,8 @@
136 ~person-name...138 ~person-name...
137 >>> print notification['X-Launchpad-Message-Rationale']139 >>> print notification['X-Launchpad-Message-Rationale']
138 Subscriber140 Subscriber
141 >>> print notification['X-Launchpad-Message-For']
142 source-subscriber
139 >>> print notification.get_payload(decode=True)143 >>> print notification.get_payload(decode=True)
140 Eric has proposed merging144 Eric has proposed merging
141 lp://dev/~person-name...into lp://dev/~person-name...145 lp://dev/~person-name...into lp://dev/~person-name...
@@ -176,11 +180,12 @@
176 >>> for notification in notifications:180 >>> for notification in notifications:
177 ... print "%s, %s" % (181 ... print "%s, %s" % (
178 ... notification['X-Envelope-To'],182 ... notification['X-Envelope-To'],
179 ... notification['X-Launchpad-Message-Rationale'])183 ... notification['X-Launchpad-Message-Rationale'],
180 bob@example.com, Reviewer184 ... notification['X-Launchpad-Message-For'])
181 mary@example.com, Reviewer185 bob@example.com, Reviewer, bob
182 source@example.com, Subscriber186 mary@example.com, Reviewer, mary
183 target@example.com, Subscriber187 source@example.com, Subscriber, source-subscriber
188 target@example.com, Subscriber, target-subscriber
184 >>> notification = notifications[0]189 >>> notification = notifications[0]
185 >>> print notification.get_payload()[0].get_payload(decode=True)190 >>> print notification.get_payload()[0].get_payload(decode=True)
186 Eric has proposed merging191 Eric has proposed merging
187192
=== modified file 'lib/lp/code/doc/branch-notifications.txt'
--- lib/lp/code/doc/branch-notifications.txt 2015-09-02 16:54:24 +0000
+++ lib/lp/code/doc/branch-notifications.txt 2015-09-11 12:44:20 +0000
@@ -60,6 +60,8 @@
60 ~name12/firefox/main60 ~name12/firefox/main
61 >>> print branch_notification['X-Launchpad-Message-Rationale']61 >>> print branch_notification['X-Launchpad-Message-Rationale']
62 Subscriber62 Subscriber
63 >>> print branch_notification['X-Launchpad-Message-For']
64 name12
63 >>> notification_body = branch_notification.get_payload(decode=True)65 >>> notification_body = branch_notification.get_payload(decode=True)
64 >>> print notification_body #doctest: -NORMALIZE_WHITESPACE66 >>> print notification_body #doctest: -NORMALIZE_WHITESPACE
65 The contents.67 The contents.
6668
=== modified file 'lib/lp/code/doc/codeimport.txt'
--- lib/lp/code/doc/codeimport.txt 2014-02-24 07:19:52 +0000
+++ lib/lp/code/doc/codeimport.txt 2015-09-11 12:44:20 +0000
@@ -100,6 +100,8 @@
100 New code import: widget/trunk-cvs100 New code import: widget/trunk-cvs
101 >>> print message['X-Launchpad-Message-Rationale']101 >>> print message['X-Launchpad-Message-Rationale']
102 Operator @vcs-imports102 Operator @vcs-imports
103 >>> print message['X-Launchpad-Message-For']
104 vcs-imports
103 >>> print message.get_payload(decode=True)105 >>> print message.get_payload(decode=True)
104 A new CVS code import has been requested by Code Import Person:106 A new CVS code import has been requested by Code Import Person:
105 http://code.launchpad.dev/~import-person/widget/trunk-cvs107 http://code.launchpad.dev/~import-person/widget/trunk-cvs
106108
=== modified file 'lib/lp/code/mail/codeimport.py'
--- lib/lp/code/mail/codeimport.py 2014-02-24 07:19:52 +0000
+++ lib/lp/code/mail/codeimport.py 2015-09-11 12:44:20 +0000
@@ -1,4 +1,4 @@
1# Copyright 2009-2011 Canonical Ltd. This software is licensed under the1# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Email notifications related to code imports."""4"""Email notifications related to code imports."""
@@ -65,6 +65,7 @@
65 headers = {'X-Launchpad-Branch': code_import.branch.unique_name,65 headers = {'X-Launchpad-Branch': code_import.branch.unique_name,
66 'X-Launchpad-Message-Rationale':66 'X-Launchpad-Message-Rationale':
67 'Operator @%s' % vcs_imports.name,67 'Operator @%s' % vcs_imports.name,
68 'X-Launchpad-Message-For': vcs_imports.name,
68 'X-Launchpad-Notification-Type': 'code-import',69 'X-Launchpad-Notification-Type': 'code-import',
69 }70 }
70 for address in get_contact_email_addresses(vcs_imports):71 for address in get_contact_email_addresses(vcs_imports):
@@ -185,6 +186,7 @@
185 else:186 else:
186 template_params['rationale'] = rationale187 template_params['rationale'] = rationale
187 template_params['unsubscribe'] = ''188 template_params['unsubscribe'] = ''
189 for_person = vcs_imports
188 else:190 else:
189 if subscription.notification_level in interested_levels:191 if subscription.notification_level in interested_levels:
190 template_params['rationale'] = (192 template_params['rationale'] = (
@@ -197,10 +199,12 @@
197 "%s/+edit-subscription." % canonical_url(branch))199 "%s/+edit-subscription." % canonical_url(branch))
198 else:200 else:
199 template_params['unsubscribe'] = ''201 template_params['unsubscribe'] = ''
202 for_person = subscription.person
200 else:203 else:
201 # Don't send email to this subscriber.204 # Don't send email to this subscriber.
202 continue205 continue
203206
204 headers['X-Launchpad-Message-Rationale'] = rationale207 headers['X-Launchpad-Message-Rationale'] = rationale
208 headers['X-Launchpad-Message-For'] = for_person.name
205 body = email_template % template_params209 body = email_template % template_params
206 simple_sendmail(from_address, email_address, subject, body, headers)210 simple_sendmail(from_address, email_address, subject, body, headers)
207211
=== modified file 'lib/lp/code/mail/tests/test_branch.py'
--- lib/lp/code/mail/tests/test_branch.py 2015-09-02 16:54:24 +0000
+++ lib/lp/code/mail/tests/test_branch.py 2015-09-11 12:44:20 +0000
@@ -227,6 +227,7 @@
227 self.assertEqual(227 self.assertEqual(
228 {'X-Launchpad-Branch': branch.unique_name,228 {'X-Launchpad-Branch': branch.unique_name,
229 'X-Launchpad-Message-Rationale': 'Subscriber',229 'X-Launchpad-Message-Rationale': 'Subscriber',
230 'X-Launchpad-Message-For': bob.name,
230 'X-Launchpad-Notification-Type': 'branch-updated',231 'X-Launchpad-Notification-Type': 'branch-updated',
231 'X-Launchpad-Project': self.getBranchProjectName(branch),232 'X-Launchpad-Project': self.getBranchProjectName(branch),
232 'Message-Id': '<foobar-example-com>'},233 'Message-Id': '<foobar-example-com>'},
@@ -247,6 +248,7 @@
247 self.assertEqual(248 self.assertEqual(
248 {'X-Launchpad-Branch': branch.unique_name,249 {'X-Launchpad-Branch': branch.unique_name,
249 'X-Launchpad-Message-Rationale': 'Subscriber',250 'X-Launchpad-Message-Rationale': 'Subscriber',
251 'X-Launchpad-Message-For': bob.name,
250 'X-Launchpad-Notification-Type': 'branch-revision',252 'X-Launchpad-Notification-Type': 'branch-revision',
251 'X-Launchpad-Branch-Revision-Number': '1',253 'X-Launchpad-Branch-Revision-Number': '1',
252 'X-Launchpad-Project': self.getBranchProjectName(branch),254 'X-Launchpad-Project': self.getBranchProjectName(branch),
253255
=== modified file 'lib/lp/code/mail/tests/test_branchmergeproposal.py'
--- lib/lp/code/mail/tests/test_branchmergeproposal.py 2015-09-02 16:54:24 +0000
+++ lib/lp/code/mail/tests/test_branchmergeproposal.py 2015-09-11 12:44:20 +0000
@@ -135,6 +135,7 @@
135 self.assertEqual(135 self.assertEqual(
136 {'X-Launchpad-Branch': bmp.source_branch.unique_name,136 {'X-Launchpad-Branch': bmp.source_branch.unique_name,
137 'X-Launchpad-Message-Rationale': 'Subscriber',137 'X-Launchpad-Message-Rationale': 'Subscriber',
138 'X-Launchpad-Message-For': subscriber.name,
138 'X-Launchpad-Notification-Type': 'code-review',139 'X-Launchpad-Notification-Type': 'code-review',
139 'X-Launchpad-Project': bmp.source_branch.product.name,140 'X-Launchpad-Project': bmp.source_branch.product.name,
140 'Reply-To': bmp.address,141 'Reply-To': bmp.address,
141142
=== modified file 'lib/lp/code/mail/tests/test_codereviewcomment.py'
--- lib/lp/code/mail/tests/test_codereviewcomment.py 2015-09-08 11:56:33 +0000
+++ lib/lp/code/mail/tests/test_codereviewcomment.py 2015-09-11 12:44:20 +0000
@@ -164,6 +164,7 @@
164 rationale = mailer._recipients.getReason('subscriber@example.com')[1]164 rationale = mailer._recipients.getReason('subscriber@example.com')[1]
165 expected = {'X-Launchpad-Branch': source_branch.unique_name,165 expected = {'X-Launchpad-Branch': source_branch.unique_name,
166 'X-Launchpad-Message-Rationale': rationale,166 'X-Launchpad-Message-Rationale': rationale,
167 'X-Launchpad-Message-For': subscriber.name,
167 'X-Launchpad-Notification-Type': 'code-review',168 'X-Launchpad-Notification-Type': 'code-review',
168 'X-Launchpad-Project': source_branch.product.name,169 'X-Launchpad-Project': source_branch.product.name,
169 'Message-Id': message.rfc822msgid,170 'Message-Id': message.rfc822msgid,
@@ -221,6 +222,7 @@
221 'You are subscribed to branch %s.' % source_branch.bzr_identity,222 'You are subscribed to branch %s.' % source_branch.bzr_identity,
222 '',223 '',
223 'Launchpad-Message-Rationale: %s' % rationale,224 'Launchpad-Message-Rationale: %s' % rationale,
225 'Launchpad-Message-For: %s' % subscriber.name,
224 'Launchpad-Notification-Type: code-review',226 'Launchpad-Notification-Type: code-review',
225 'Launchpad-Branch: %s' % source_branch.unique_name,227 'Launchpad-Branch: %s' % source_branch.unique_name,
226 'Launchpad-Project: %s' % source_branch.product.name,228 'Launchpad-Project: %s' % source_branch.product.name,
227229
=== modified file 'lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py'
--- lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py 2015-09-02 16:54:24 +0000
+++ lib/lp/code/mail/tests/test_sourcepackagerecipebuild.py 2015-09-11 12:44:20 +0000
@@ -84,6 +84,8 @@
84 self.assertEqual(84 self.assertEqual(
85 'Requester', ctrl.headers['X-Launchpad-Message-Rationale'])85 'Requester', ctrl.headers['X-Launchpad-Message-Rationale'])
86 self.assertEqual(86 self.assertEqual(
87 build.requester.name, ctrl.headers['X-Launchpad-Message-For'])
88 self.assertEqual(
87 'recipe-build-status',89 'recipe-build-status',
88 ctrl.headers['X-Launchpad-Notification-Type'])90 ctrl.headers['X-Launchpad-Notification-Type'])
89 self.assertEqual(91 self.assertEqual(
@@ -119,6 +121,8 @@
119 self.assertEqual(121 self.assertEqual(
120 'Requester', ctrl.headers['X-Launchpad-Message-Rationale'])122 'Requester', ctrl.headers['X-Launchpad-Message-Rationale'])
121 self.assertEqual(123 self.assertEqual(
124 build.requester.name, ctrl.headers['X-Launchpad-Message-For'])
125 self.assertEqual(
122 'recipe-build-status',126 'recipe-build-status',
123 ctrl.headers['X-Launchpad-Notification-Type'])127 ctrl.headers['X-Launchpad-Notification-Type'])
124 self.assertEqual(128 self.assertEqual(
125129
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py 2015-08-06 16:48:48 +0000
+++ lib/lp/registry/browser/person.py 2015-09-11 12:44:20 +0000
@@ -4327,7 +4327,7 @@
4327 return4327 return
4328 try:4328 try:
4329 send_direct_contact_email(4329 send_direct_contact_email(
4330 sender_email, self.recipients, subject, message)4330 sender_email, self.recipients, self.context, subject, message)
4331 except QuotaReachedError as error:4331 except QuotaReachedError as error:
4332 fmt_date = DateTimeFormatterAPI(self.next_try)4332 fmt_date = DateTimeFormatterAPI(self.next_try)
4333 self.request.response.addErrorNotification(4333 self.request.response.addErrorNotification(
43344334
=== modified file 'lib/lp/registry/doc/teammembership-email-notification.txt'
--- lib/lp/registry/doc/teammembership-email-notification.txt 2015-09-02 02:46:18 +0000
+++ lib/lp/registry/doc/teammembership-email-notification.txt 2015-09-11 12:44:20 +0000
@@ -1067,10 +1067,11 @@
1067 ... name='team-two', email='team-two@example.com', owner=owner)1067 ... name='team-two', email='team-two@example.com', owner=owner)
1068 >>> ignored = team_one.addMember(team_two, owner, force_team_add=True)1068 >>> ignored = team_one.addMember(team_two, owner, force_team_add=True)
1069 >>> run_mail_jobs()1069 >>> run_mail_jobs()
1070 >>> print_distinct_emails()1070 >>> print_distinct_emails(include_for=True)
1071 From: Team One ...1071 From: Team One ...
1072 To: Team Two <team-two...>1072 To: Team Two <team-two...>
1073 X-Launchpad-Message-Rationale: Member (team-one) @team-two1073 X-Launchpad-Message-Rationale: Member (team-one) @team-two
1074 X-Launchpad-Message-For: team-two
1074 X-Launchpad-Notification-Type: team-membership-new1075 X-Launchpad-Notification-Type: team-membership-new
1075 Subject: team-two joined team-one1076 Subject: team-two joined team-one
1076 <BLANKLINE>1077 <BLANKLINE>
10771078
=== modified file 'lib/lp/registry/mail/notification.py'
--- lib/lp/registry/mail/notification.py 2015-09-02 02:46:18 +0000
+++ lib/lp/registry/mail/notification.py 2015-09-11 12:44:20 +0000
@@ -157,13 +157,15 @@
157157
158158
159def send_direct_contact_email(159def send_direct_contact_email(
160 sender_email, recipients_set, subject, body):160 sender_email, recipients_set, person_or_team, subject, body):
161 """Send a direct user-to-user email.161 """Send a direct user-to-user email.
162162
163 :param sender_email: The email address of the sender.163 :param sender_email: The email address of the sender.
164 :type sender_email: string164 :type sender_email: string
165 :param recipients_set: The recipients.165 :param recipients_set: The recipients.
166 :type recipients_set:' A ContactViaWebNotificationSet166 :type recipients_set: `ContactViaWebNotificationSet`
167 :param person_or_team: The party that is the context of the email.
168 :type person_or_team: `IPerson`
167 :param subject: The Subject header.169 :param subject: The Subject header.
168 :type subject: unicode170 :type subject: unicode
169 :param body: The message body.171 :param body: The message body.
@@ -209,7 +211,7 @@
209 message = None211 message = None
210 for recipient_email, recipient in recipients_set.getRecipientPersons():212 for recipient_email, recipient in recipients_set.getRecipientPersons():
211 recipient_name = str(encode(recipient.displayname))213 recipient_name = str(encode(recipient.displayname))
212 reason, rational_header = recipients_set.getReason(recipient_email)214 reason, rationale_header = recipients_set.getReason(recipient_email)
213 reason = str(encode(reason)).replace('\n ', '\n')215 reason = str(encode(reason)).replace('\n ', '\n')
214 formatted_body = mailwrapper.format(body, force_wrap=True)216 formatted_body = mailwrapper.format(body, force_wrap=True)
215 formatted_body += additions % reason217 formatted_body += additions % reason
@@ -219,7 +221,8 @@
219 message['To'] = formataddr((recipient_name, recipient_email))221 message['To'] = formataddr((recipient_name, recipient_email))
220 message['Subject'] = subject_header222 message['Subject'] = subject_header
221 message['Message-ID'] = make_msgid('launchpad')223 message['Message-ID'] = make_msgid('launchpad')
222 message['X-Launchpad-Message-Rationale'] = rational_header224 message['X-Launchpad-Message-Rationale'] = rationale_header
225 message['X-Launchpad-Message-For'] = person_or_team.name
223 # Send the message.226 # Send the message.
224 sendmail(message, bulk=False)227 sendmail(message, bulk=False)
225 # Use the information from the last message sent to record the action228 # Use the information from the last message sent to record the action
226229
=== modified file 'lib/lp/registry/model/productjob.py'
--- lib/lp/registry/model/productjob.py 2015-07-09 20:06:17 +0000
+++ lib/lp/registry/model/productjob.py 2015-09-11 12:44:20 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012 Canonical Ltd. This software is licensed under the1# Copyright 2012-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Jobs classes to update products and send notifications."""4"""Jobs classes to update products and send notifications."""
@@ -321,6 +321,7 @@
321 'X-Launchpad-Project':321 'X-Launchpad-Project':
322 '%(product_displayname)s (%(product_name)s)' % message_data,322 '%(product_displayname)s (%(product_name)s)' % message_data,
323 'X-Launchpad-Message-Rationale': rationale,323 'X-Launchpad-Message-Rationale': rationale,
324 'X-Launchpad-Message-For': self.product.owner.name,
324 }325 }
325 if reply_to is not None:326 if reply_to is not None:
326 headers['Reply-To'] = reply_to327 headers['Reply-To'] = reply_to
327328
=== modified file 'lib/lp/registry/tests/test_notification.py'
--- lib/lp/registry/tests/test_notification.py 2012-12-26 01:04:05 +0000
+++ lib/lp/registry/tests/test_notification.py 2015-09-11 12:44:20 +0000
@@ -1,4 +1,4 @@
1# Copyright 2012 Canonical Ltd. This software is licensed under the1# Copyright 2012-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test notification classes and functions."""4"""Test notification classes and functions."""
@@ -28,7 +28,8 @@
28 recipients_set = NotificationRecipientSet()28 recipients_set = NotificationRecipientSet()
29 recipients_set.add(user, 'test reason', 'test rationale')29 recipients_set.add(user, 'test reason', 'test rationale')
30 pop_notifications()30 pop_notifications()
31 send_direct_contact_email('me@eg.dom', recipients_set, subject, body)31 send_direct_contact_email(
32 'me@eg.dom', recipients_set, user, subject, body)
32 notifications = pop_notifications()33 notifications = pop_notifications()
33 notification = notifications[0]34 notification = notifications[0]
34 self.assertEqual(1, len(notifications))35 self.assertEqual(1, len(notifications))
@@ -37,6 +38,7 @@
37 self.assertEqual(subject, notification['Subject'])38 self.assertEqual(subject, notification['Subject'])
38 self.assertEqual(39 self.assertEqual(
39 'test rationale', notification['X-Launchpad-Message-Rationale'])40 'test rationale', notification['X-Launchpad-Message-Rationale'])
41 self.assertEqual(user.name, notification['X-Launchpad-Message-For'])
40 self.assertIs(None, notification['Precedence'])42 self.assertIs(None, notification['Precedence'])
41 self.assertTrue('launchpad' in notification['Message-ID'])43 self.assertTrue('launchpad' in notification['Message-ID'])
42 self.assertEqual(44 self.assertEqual(
@@ -61,7 +63,7 @@
61 authorization.record(old_message)63 authorization.record(old_message)
62 self.assertRaises(64 self.assertRaises(
63 QuotaReachedError, send_direct_contact_email,65 QuotaReachedError, send_direct_contact_email,
64 'me@eg.dom', recipients_set, 'subject', 'body')66 'me@eg.dom', recipients_set, user, 'subject', 'body')
6567
66 def test_empty_recipient_set(self):68 def test_empty_recipient_set(self):
67 # The recipient set can be empty. No messages are sent and the69 # The recipient set can be empty. No messages are sent and the
@@ -75,7 +77,7 @@
75 authorization.record(old_message)77 authorization.record(old_message)
76 pop_notifications()78 pop_notifications()
77 send_direct_contact_email(79 send_direct_contact_email(
78 'me@eg.dom', recipients_set, 'subject', 'body')80 'me@eg.dom', recipients_set, user, 'subject', 'body')
79 notifications = pop_notifications()81 notifications = pop_notifications()
80 self.assertEqual(0, len(notifications))82 self.assertEqual(0, len(notifications))
81 self.assertTrue(authorization.is_allowed)83 self.assertTrue(authorization.is_allowed)
@@ -87,7 +89,8 @@
87 recipients_set.add(user, 'test reason', 'test rationale')89 recipients_set.add(user, 'test reason', 'test rationale')
88 pop_notifications()90 pop_notifications()
89 body = 'Can you help me? ' * 891 body = 'Can you help me? ' * 8
90 send_direct_contact_email('me@eg.dom', recipients_set, 'subject', body)92 send_direct_contact_email(
93 'me@eg.dom', recipients_set, user, 'subject', body)
91 notifications = pop_notifications()94 notifications = pop_notifications()
92 body, footer = notifications[0].get_payload().split('-- ')95 body, footer = notifications[0].get_payload().split('-- ')
93 self.assertEqual(96 self.assertEqual(
@@ -105,7 +108,8 @@
105 recipients_set = NotificationRecipientSet()108 recipients_set = NotificationRecipientSet()
106 recipients_set.add(user, 'test reason', 'test rationale')109 recipients_set.add(user, 'test reason', 'test rationale')
107 pop_notifications()110 pop_notifications()
108 send_direct_contact_email('me@eg.dom', recipients_set, 'test', 'test')111 send_direct_contact_email(
112 'me@eg.dom', recipients_set, user, 'test', 'test')
109 notifications = pop_notifications()113 notifications = pop_notifications()
110 notification = notifications[0]114 notification = notifications[0]
111 self.assertEqual(115 self.assertEqual(
112116
=== modified file 'lib/lp/registry/tests/test_productjob.py'
--- lib/lp/registry/tests/test_productjob.py 2015-07-08 16:05:11 +0000
+++ lib/lp/registry/tests/test_productjob.py 2015-09-11 12:44:20 +0000
@@ -1,4 +1,4 @@
1# Copyright 2010-2012 Canonical Ltd. This software is licensed under the1# Copyright 2010-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for ProductJobs."""4"""Tests for ProductJobs."""
@@ -442,6 +442,7 @@
442 ('X-Launchpad-Project', '%s (%s)' %442 ('X-Launchpad-Project', '%s (%s)' %
443 (product.displayname, product.name)),443 (product.displayname, product.name)),
444 ('X-Launchpad-Message-Rationale', 'Maintainer'),444 ('X-Launchpad-Message-Rationale', 'Maintainer'),
445 ('X-Launchpad-Message-For', product.owner.name),
445 ('Reply-To', reply_to),446 ('Reply-To', reply_to),
446 ]447 ]
447 self.assertContentEqual(expected_headers, headers.items())448 self.assertContentEqual(expected_headers, headers.items())
@@ -458,6 +459,7 @@
458 ('X-Launchpad-Project', '%s (%s)' %459 ('X-Launchpad-Project', '%s (%s)' %
459 (product.displayname, product.name)),460 (product.displayname, product.name)),
460 ('X-Launchpad-Message-Rationale', 'Maintainer'),461 ('X-Launchpad-Message-Rationale', 'Maintainer'),
462 ('X-Launchpad-Message-For', product.owner.name),
461 ]463 ]
462 self.assertContentEqual(expected_headers, headers.items())464 self.assertContentEqual(expected_headers, headers.items())
463465
464466
=== modified file 'lib/lp/services/mail/basemailer.py'
--- lib/lp/services/mail/basemailer.py 2015-08-27 14:34:21 +0000
+++ lib/lp/services/mail/basemailer.py 2015-09-11 12:44:20 +0000
@@ -123,6 +123,8 @@
123 reason, rationale = self._recipients.getReason(email)123 reason, rationale = self._recipients.getReason(email)
124 headers = OrderedDict()124 headers = OrderedDict()
125 headers['X-Launchpad-Message-Rationale'] = reason.mail_header125 headers['X-Launchpad-Message-Rationale'] = reason.mail_header
126 if reason.subscriber.name is not None:
127 headers['X-Launchpad-Message-For'] = reason.subscriber.name
126 if self.notification_type is not None:128 if self.notification_type is not None:
127 headers['X-Launchpad-Notification-Type'] = self.notification_type129 headers['X-Launchpad-Notification-Type'] = self.notification_type
128 reply_to = self._getReplyToAddress(email, recipient)130 reply_to = self._getReplyToAddress(email, recipient)
129131
=== modified file 'lib/lp/services/mail/notificationrecipientset.py'
--- lib/lp/services/mail/notificationrecipientset.py 2015-08-26 13:41:21 +0000
+++ lib/lp/services/mail/notificationrecipientset.py 2015-09-11 12:44:20 +0000
@@ -29,6 +29,7 @@
29 correspond to a real Person.29 correspond to a real Person.
30 """30 """
3131
32 name = None
32 displayname = None33 displayname = None
33 is_team = False34 is_team = False
34 expanded_notification_footers = False35 expanded_notification_footers = False
3536
=== modified file 'lib/lp/services/mail/tests/test_basemailer.py'
--- lib/lp/services/mail/tests/test_basemailer.py 2015-08-23 22:53:55 +0000
+++ lib/lp/services/mail/tests/test_basemailer.py 2015-09-11 12:44:20 +0000
@@ -168,7 +168,8 @@
168 def test_generateEmail_append_expanded_footer(self):168 def test_generateEmail_append_expanded_footer(self):
169 # Recipients with expanded_notification_footers receive an expanded169 # Recipients with expanded_notification_footers receive an expanded
170 # footer on messages.170 # footer on messages.
171 fake_to = self.factory.makePerson(email='to@example.com')171 fake_to = self.factory.makePerson(
172 name='to-person', email='to@example.com')
172 fake_to.expanded_notification_footers = True173 fake_to.expanded_notification_footers = True
173 recipients = {fake_to: FakeSubscription()}174 recipients = {fake_to: FakeSubscription()}
174 mailer = BaseMailerSubclass(175 mailer = BaseMailerSubclass(
@@ -179,6 +180,7 @@
179 ctrl.body, EndsWith(180 ctrl.body, EndsWith(
180 '\n-- \n'181 '\n-- \n'
181 'Launchpad-Message-Rationale: pete\n'182 'Launchpad-Message-Rationale: pete\n'
183 'Launchpad-Message-For: to-person\n'
182 'Launchpad-Notification-Type: test\n'))184 'Launchpad-Notification-Type: test\n'))
183185
184 def test_sendall_single_failure_doesnt_kill_all(self):186 def test_sendall_single_failure_doesnt_kill_all(self):
185187
=== modified file 'lib/lp/snappy/tests/test_snapbuild.py'
--- lib/lp/snappy/tests/test_snapbuild.py 2015-08-03 13:20:45 +0000
+++ lib/lp/snappy/tests/test_snapbuild.py 2015-09-11 12:44:20 +0000
@@ -255,6 +255,7 @@
255 "unstable" % build.id, subject)255 "unstable" % build.id, subject)
256 self.assertEqual(256 self.assertEqual(
257 "Requester", notification["X-Launchpad-Message-Rationale"])257 "Requester", notification["X-Launchpad-Message-Rationale"])
258 self.assertEqual(person.name, notification["X-Launchpad-Message-For"])
258 self.assertEqual(259 self.assertEqual(
259 "snap-build-status",260 "snap-build-status",
260 notification["X-Launchpad-Notification-Type"])261 notification["X-Launchpad-Notification-Type"])
261262
=== modified file 'lib/lp/soyuz/mail/tests/test_packageupload.py'
--- lib/lp/soyuz/mail/tests/test_packageupload.py 2015-08-25 23:27:09 +0000
+++ lib/lp/soyuz/mail/tests/test_packageupload.py 2015-09-11 12:44:20 +0000
@@ -132,6 +132,7 @@
132 "X-Launchpad-Message-Rationale": Equals("Announcement"),132 "X-Launchpad-Message-Rationale": Equals("Announcement"),
133 "X-Launchpad-Notification-Type": Equals("package-upload"),133 "X-Launchpad-Notification-Type": Equals("package-upload"),
134 }))134 }))
135 self.assertNotIn("X-Launchpad-Message-For", dict(notifications[1]))
135136
136 def test_forAction_announce_from_person_override_with_unicode_names(self):137 def test_forAction_announce_from_person_override_with_unicode_names(self):
137 # PackageUploadMailer.forAction() takes an optional138 # PackageUploadMailer.forAction() takes an optional
@@ -164,6 +165,7 @@
164 "X-Launchpad-Message-Rationale": Equals("Announcement"),165 "X-Launchpad-Message-Rationale": Equals("Announcement"),
165 "X-Launchpad-Notification-Type": Equals("package-upload"),166 "X-Launchpad-Notification-Type": Equals("package-upload"),
166 }))167 }))
168 self.assertNotIn("X-Launchpad-Message-For", dict(notifications[1]))
167169
168 def test_forAction_bcc_to_derivatives_list(self):170 def test_forAction_bcc_to_derivatives_list(self):
169 # PackageUploadMailer.forAction() will BCC the announcement email to171 # PackageUploadMailer.forAction() will BCC the announcement email to
@@ -186,6 +188,7 @@
186 "X-Launchpad-Message-Rationale": Equals("Announcement"),188 "X-Launchpad-Message-Rationale": Equals("Announcement"),
187 "X-Launchpad-Notification-Type": Equals("package-upload"),189 "X-Launchpad-Notification-Type": Equals("package-upload"),
188 }))190 }))
191 self.assertNotIn("X-Launchpad-Message-For", dict(notifications[1]))
189192
190 def test_fetch_information_spr_multiple_changelogs(self):193 def test_fetch_information_spr_multiple_changelogs(self):
191 # If previous_version is passed the "changelog" entry in the194 # If previous_version is passed the "changelog" entry in the
@@ -454,15 +457,17 @@
454 "accepted", blamer, spr, [], [], archive, distroseries,457 "accepted", blamer, spr, [], [], archive, distroseries,
455 PackagePublishingPocket.RELEASE, changes=changes)458 PackagePublishingPocket.RELEASE, changes=changes)
456 recipients = dict(mailer._recipients.getRecipientPersons())459 recipients = dict(mailer._recipients.getRecipientPersons())
457 for email, rationale in (460 for person, rationale in (
458 (blamer.preferredemail.email, "Requester"),461 (blamer, "Requester"),
459 ("maintainer@example.com", "Maintainer"),462 (maintainer, "Maintainer"),
460 ("changer@example.com", "Changed-By")):463 (changer, "Changed-By")):
464 email = person.preferredemail.email
461 headers = mailer._getHeaders(email, recipients[email])465 headers = mailer._getHeaders(email, recipients[email])
462 self.assertThat(466 self.assertThat(
463 headers,467 headers,
464 ContainsDict({468 ContainsDict({
465 "X-Launchpad-Message-Rationale": Equals(rationale),469 "X-Launchpad-Message-Rationale": Equals(rationale),
470 "X-Launchpad-Message-For": Equals(person.name),
466 "X-Launchpad-Notification-Type": Equals("package-upload"),471 "X-Launchpad-Notification-Type": Equals("package-upload"),
467 "X-Katie": Equals("Launchpad actually"),472 "X-Katie": Equals("Launchpad actually"),
468 "X-Launchpad-Archive": Equals(archive.reference),473 "X-Launchpad-Archive": Equals(archive.reference),
@@ -497,14 +502,16 @@
497 "accepted", blamer, spr, [], [], archive, distroseries,502 "accepted", blamer, spr, [], [], archive, distroseries,
498 PackagePublishingPocket.RELEASE, changes=changes)503 PackagePublishingPocket.RELEASE, changes=changes)
499 recipients = dict(mailer._recipients.getRecipientPersons())504 recipients = dict(mailer._recipients.getRecipientPersons())
500 for email, rationale in (505 for person, rationale in (
501 (blamer.preferredemail.email, "Requester"),506 (blamer, "Requester"),
502 (uploader.preferredemail.email, "PPA Uploader")):507 (uploader, "PPA Uploader")):
508 email = person.preferredemail.email
503 headers = mailer._getHeaders(email, recipients[email])509 headers = mailer._getHeaders(email, recipients[email])
504 self.assertThat(510 self.assertThat(
505 headers,511 headers,
506 ContainsDict({512 ContainsDict({
507 "X-Launchpad-Message-Rationale": Equals(rationale),513 "X-Launchpad-Message-Rationale": Equals(rationale),
514 "X-Launchpad-Message-For": Equals(person.name),
508 "X-Launchpad-Notification-Type": Equals("package-upload"),515 "X-Launchpad-Notification-Type": Equals("package-upload"),
509 "X-Katie": Equals("Launchpad actually"),516 "X-Katie": Equals("Launchpad actually"),
510 "X-Launchpad-Archive": Equals(archive.reference),517 "X-Launchpad-Archive": Equals(archive.reference),
511518
=== modified file 'lib/lp/soyuz/tests/test_build_notify.py'
--- lib/lp/soyuz/tests/test_build_notify.py 2015-09-04 12:19:07 +0000
+++ lib/lp/soyuz/tests/test_build_notify.py 2015-09-11 12:44:20 +0000
@@ -105,10 +105,13 @@
105 format_address_for_person(recipient), notification['To'])105 format_address_for_person(recipient), notification['To'])
106 if reason == "buildd-admin":106 if reason == "buildd-admin":
107 rationale = "Buildd-Admin @launchpad-buildd-admins"107 rationale = "Buildd-Admin @launchpad-buildd-admins"
108 expected_for = "launchpad-buildd-admins"
108 else:109 else:
109 rationale = reason.title()110 rationale = reason.title()
111 expected_for = recipient.name
110 self.assertEqual(112 self.assertEqual(
111 rationale, notification['X-Launchpad-Message-Rationale'])113 rationale, notification['X-Launchpad-Message-Rationale'])
114 self.assertEqual(expected_for, notification['X-Launchpad-Message-For'])
112 self.assertEqual(115 self.assertEqual(
113 'package-build-status',116 'package-build-status',
114 notification['X-Launchpad-Notification-Type'])117 notification['X-Launchpad-Notification-Type'])
115118
=== modified file 'lib/lp/soyuz/tests/test_livefsbuild.py'
--- lib/lp/soyuz/tests/test_livefsbuild.py 2015-08-03 12:59:18 +0000
+++ lib/lp/soyuz/tests/test_livefsbuild.py 2015-09-11 12:44:20 +0000
@@ -1,4 +1,4 @@
1# Copyright 2014 Canonical Ltd. This software is licensed under the1# Copyright 2014-2015 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Test live filesystem build features."""4"""Test live filesystem build features."""
@@ -257,6 +257,7 @@
257 "unstable" % build.id, subject)257 "unstable" % build.id, subject)
258 self.assertEqual(258 self.assertEqual(
259 "Requester", notification["X-Launchpad-Message-Rationale"])259 "Requester", notification["X-Launchpad-Message-Rationale"])
260 self.assertEqual(person.name, notification["X-Launchpad-Message-For"])
260 self.assertEqual(261 self.assertEqual(
261 "livefs-build-status",262 "livefs-build-status",
262 notification["X-Launchpad-Notification-Type"])263 notification["X-Launchpad-Notification-Type"])
263264
=== modified file 'lib/lp/testing/mail_helpers.py'
--- lib/lp/testing/mail_helpers.py 2015-09-02 02:46:18 +0000
+++ lib/lp/testing/mail_helpers.py 2015-09-11 12:44:20 +0000
@@ -60,8 +60,8 @@
6060
6161
62def print_emails(include_reply_to=False, group_similar=False,62def print_emails(include_reply_to=False, group_similar=False,
63 include_rationale=False, notifications=None,63 include_rationale=False, include_for=False,
64 include_notification_type=False):64 notifications=None, include_notification_type=False):
65 """Pop all messages from stub.test_emails and print them with65 """Pop all messages from stub.test_emails and print them with
66 their recipients.66 their recipients.
6767
@@ -76,6 +76,7 @@
76 :param group_similar: Group messages sent to multiple recipients if True.76 :param group_similar: Group messages sent to multiple recipients if True.
77 :param include_rationale: Include the X-Launchpad-Message-Rationale77 :param include_rationale: Include the X-Launchpad-Message-Rationale
78 header.78 header.
79 :param include_for: Include the X-Launchpad-Message-For header.
79 :param notifications: Use the provided list of notifications instead of80 :param notifications: Use the provided list of notifications instead of
80 the stack.81 the stack.
81 :param include_notification_type: Include the82 :param include_notification_type: Include the
@@ -106,8 +107,10 @@
106 print 'Reply-To:', message['Reply-To']107 print 'Reply-To:', message['Reply-To']
107 rationale_header = 'X-Launchpad-Message-Rationale'108 rationale_header = 'X-Launchpad-Message-Rationale'
108 if include_rationale and rationale_header in message:109 if include_rationale and rationale_header in message:
109 print (110 print '%s: %s' % (rationale_header, message[rationale_header])
110 '%s: %s' % (rationale_header, message[rationale_header]))111 for_header = 'X-Launchpad-Message-For'
112 if include_for and for_header in message:
113 print '%s: %s' % (for_header, message[for_header])
111 notification_type_header = 'X-Launchpad-Notification-Type'114 notification_type_header = 'X-Launchpad-Notification-Type'
112 if include_notification_type and notification_type_header in message:115 if include_notification_type and notification_type_header in message:
113 print '%s: %s' % (116 print '%s: %s' % (
@@ -118,11 +121,12 @@
118121
119122
120def print_distinct_emails(include_reply_to=False, include_rationale=True,123def print_distinct_emails(include_reply_to=False, include_rationale=True,
121 include_notification_type=True):124 include_for=False, include_notification_type=True):
122 """A convenient shortcut for `print_emails`(group_similar=True)."""125 """A convenient shortcut for `print_emails`(group_similar=True)."""
123 return print_emails(group_similar=True,126 return print_emails(group_similar=True,
124 include_reply_to=include_reply_to,127 include_reply_to=include_reply_to,
125 include_rationale=include_rationale,128 include_rationale=include_rationale,
129 include_for=include_for,
126 include_notification_type=include_notification_type)130 include_notification_type=include_notification_type)
127131
128132