Merge lp:~benji/launchpad/bug-784575-message into lp:launchpad
- bug-784575-message
- Merge into devel
Status: | Rejected |
---|---|
Rejected by: | Benji York |
Proposed branch: | lp:~benji/launchpad/bug-784575-message |
Merge into: | lp:launchpad |
Diff against target: |
1073 lines (+344/-362) 7 files modified
lib/lp/bugs/doc/bugnotification-sending.txt (+17/-80) lib/lp/bugs/emailtemplates/bug-notification-verbose.txt (+1/-1) lib/lp/bugs/emailtemplates/bug-notification.txt (+1/-1) lib/lp/bugs/scripts/bugnotification.py (+12/-10) lib/lp/bugs/scripts/tests/test_bugnotification.py (+52/-12) lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt (+247/-251) lib/lp/bugs/stories/xx-bugs-statistics-portlet.txt (+14/-7) |
To merge this branch: | bzr merge lp:~benji/launchpad/bug-784575-message |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jeroen T. Vermeulen (community) | code | Approve | |
Review via email: mp+62157@code.launchpad.net |
Commit message
Description of the change
Bug 784575 is about changing bug notification email to point to the new
bug +subscriptions page to manage subscriptions. This branch does that.
The change itself (in bugnotification.py, bug-notificatio
and bug-notificatio
The remainder of this branch is fixing tests to account for the new
message. Instead of blindly substituting in the new message text I took
the time to understand the tests in question and tweak them so that in
many cases they no longer unneccesarily test for the parts of the
noficiation messages that aren't pertinant to the test in question.
Another large chunk of this branch is the pure lint fix of
xx-bug-
other change was made to the file, but this prep will help a follow-on
branch.
I ran all of the lp.bugs tests to be sure nothing had broken:
bin/test -c -m lp.bugs
Some lint is left:
./lib/lp/
3: Line has trailing whitespace.
./lib/lp/
3: Line has trailing whitespace.
./lib/lp/
274: want exceeds 78 characters.
327: want exceeds 78 characters.
The bug notification templates have a trailing space on the signature
separator which is common and encouraged, so I'm leaving those (and it
occurs to me that they need a test... there I added one as
TestNotificatio
The two long lines in xx-bug-
can do as far as I can tell. If the original test author had written
down what they were testing with those assertions maybe I could do
better.
Benji York (benji) wrote : | # |
On Wed, May 25, 2011 at 1:09 AM, Jeroen T. Vermeulen <email address hidden> wrote:
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -193,25 +193,26 @@
> data['filter descriptions'])
> else:
> filters_text = u""
> - # XXX deryck 2009-11-17 Bug #484319
> - # This should be refactored to add a link inside the
> - # code where we build `reason`. However, this will
> - # require some extra work, and this small change now
> - # will ease pain for a lot of unhappy users.
> - if 'direct subscriber' in reason and 'member of' not in reason:
> - unsubscribe_notice = ('To unsubscribe from this bug, go to:\n'
> - '%s/+subscribe' % canonical_
> +
> + # In the rare case of a bug with no bugtasks, we can't generate the
> + # subscription management URL so just leave off the subscription
> + # management message entirely.
> + if len(bug.bugtasks):
> + bug_url = canonical_
> + notification_url = bug_url + '/+subscriptions'
> + subscriptions_
> + 'go to:\n%s' % notification_url)
>
> While you're here, could you also fix the line break on that last
> string,
I'm afraid I don't follow. Do you mean like so?
'To manage notifications about this bug go to:\n%s'
% notification_url)
That does read better, so I'll change it to that, but if you meant
something else, I'm curious to know what.
> and use double quotes so we don't have panic and kitchen fires
> when an apostrophe shows up?
I'm a double-
all the "MP for the textbooks" stuff that I'll cave. ;)
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
>
> @@ -1145,7 +1149,55 @@
> bug = self.product.
> notifications = IStore(
> BugNotification,
> - BugNotification
> + BugNotification.id == BugNotification
> BugNotification
> BugNotification.bug == bug)
> self.assertTrue
> +
> +
> +class TestManageNotif
> + # See bug 784575.
>
> Is this bug worth a whole test case though? Surely the test would fit
> comfortably into some other test case?
I couldn't find a good spot. Most of the tests for this code are
doctests and since we have a a moratorium on new doctests I figured
adding a point test case was the best option. I'll look again to see if
I can find a good spot... Nope...
Benji York (benji) wrote : | # |
On Wed, May 25, 2011 at 11:09 AM, Benji York <email address hidden> wrote:
> On Wed, May 25, 2011 at 1:09 AM, Jeroen T. Vermeulen <email address hidden> wrote:
>> + (message,) = construct_
>>
>> The "[2]" is very obscure. That's why we generally prefer to drill
>> into tuples by unpacking them:
>>
>> filtered_notifs, omitted_notifs, messages = construct_
>> [notification])
>> (message, ) = messages
>
> My preferences fall the other way (i.e., not minding the indexing and
> disliking the unused names), but I'll go with your request.
>
> I did combine the two expressions into one though:
>
> filtered, omitted, (message,) = construct_
> [notification])
Nope, that won't work. The linter shares my dislike for unused names.
I ended up with this instead:
_, _, (message,) = construct_
--
Benji York
Jeroen T. Vermeulen (jtv) wrote : | # |
> On Wed, May 25, 2011 at 1:09 AM, Jeroen T. Vermeulen <email address hidden>
> wrote:
> > While you're here, could you also fix the line break on that last
> > string,
>
> I'm afraid I don't follow. Do you mean like so?
>
> subscriptions_
> 'To manage notifications about this bug go to:\n%s'
> % notification_url)
>
> That does read better, so I'll change it to that, but if you meant
> something else, I'm curious to know what.
You did follow after all then. :)
> > and use double quotes so we don't have panic and kitchen fires
> > when an apostrophe shows up?
>
> I'm a double-
> all the "MP for the textbooks" stuff that I'll cave. ;)
*Evil chuckle*
> > === modified file 'lib/lp/
> > --- lib/lp/
> +0000
> > +++ lib/lp/
> +0000
> > Is this bug worth a whole test case though? Surely the test would fit
> > comfortably into some other test case?
>
> I couldn't find a good spot. Most of the tests for this code are
> doctests and since we have a a moratorium on new doctests I figured
> adding a point test case was the best option. I'll look again to see if
> I can find a good spot... Nope, this looks like the best thing to do.
No worries then.
> > + (message,) = construct_
> >
> > The "[2]" is very obscure. That's why we generally prefer to drill
> > into tuples by unpacking them:
> >
> > filtered_notifs, omitted_notifs, messages =
> construct_
> > [notification])
> > (message, ) = messages
>
> My preferences fall the other way (i.e., not minding the indexing and
> disliking the unused names), but I'll go with your request.
…but it turned out that "make lint" didn't like that. Annoying, that: the unpacking was once a solid rule. Using "_" as the variable name is one way out, but doesn't combine very well with the existence of gettext. This is where I throw my hands up and stop offering clever advice.
> I did combine the two expressions into one though:
>
> filtered, omitted, (message,) = construct_
> [notification])
Didn't know python was smart enough to match that, and never dared try!
Jeroen
Preview Diff
1 | === modified file 'lib/lp/bugs/doc/bugnotification-sending.txt' |
2 | --- lib/lp/bugs/doc/bugnotification-sending.txt 2011-05-18 13:00:11 +0000 |
3 | +++ lib/lp/bugs/doc/bugnotification-sending.txt 2011-05-25 16:14:50 +0000 |
4 | @@ -76,12 +76,6 @@ |
5 | a comment. |
6 | <BLANKLINE> |
7 | ... |
8 | - You received this bug notification because you are subscribed to |
9 | - mozilla-firefox in Ubuntu. |
10 | - http://bugs.launchpad.dev/bugs/1 |
11 | - <BLANKLINE> |
12 | - Title: |
13 | - Firefox does not support SVG |
14 | ---------------------------------------------------------------------- |
15 | To: mark@example.com |
16 | From: Sample Person <1@bugs.launchpad.net> |
17 | @@ -91,11 +85,6 @@ |
18 | a comment. |
19 | <BLANKLINE> |
20 | ... |
21 | - You received this bug notification because you are a bug assignee. |
22 | - http://bugs.launchpad.dev/bugs/1 |
23 | - <BLANKLINE> |
24 | - Title: |
25 | - Firefox does not support SVG |
26 | ---------------------------------------------------------------------- |
27 | To: support@ubuntu.com |
28 | From: Sample Person <1@bugs.launchpad.net> |
29 | @@ -104,13 +93,7 @@ |
30 | <BLANKLINE> |
31 | a comment. |
32 | <BLANKLINE> |
33 | - -- |
34 | - You received this bug notification because you are a member of Ubuntu |
35 | - Team, which is the registrant for Ubuntu. |
36 | - http://bugs.launchpad.dev/bugs/1 |
37 | - <BLANKLINE> |
38 | - Title: |
39 | - Firefox does not support SVG |
40 | + ... |
41 | ---------------------------------------------------------------------- |
42 | To: test@canonical.com |
43 | From: Sample Person <1@bugs.launchpad.net> |
44 | @@ -120,14 +103,6 @@ |
45 | a comment. |
46 | <BLANKLINE> |
47 | ... |
48 | - You received this bug notification because you are a direct subscriber |
49 | - of the bug. |
50 | - http://bugs.launchpad.dev/bugs/1 |
51 | - <BLANKLINE> |
52 | - Title: |
53 | - Firefox does not support SVG |
54 | - <BLANKLINE> |
55 | - ... |
56 | ---------------------------------------------------------------------- |
57 | |
58 | You can see that the message above contains the bug's initial comment's |
59 | @@ -192,13 +167,7 @@ |
60 | <BLANKLINE> |
61 | a new comment. |
62 | <BLANKLINE> |
63 | - -- |
64 | - You received this bug notification because you are a member of Ubuntu |
65 | - Team, which is the registrant for Ubuntu. |
66 | - http://bugs.launchpad.dev/bugs/1 |
67 | - <BLANKLINE> |
68 | - Title: |
69 | - Firefox does not support SVG |
70 | + ... |
71 | ---------------------------------------------------------------------- |
72 | To: test@canonical.com |
73 | ... |
74 | @@ -242,13 +211,8 @@ |
75 | <BLANKLINE> |
76 | ** Visibility changed to: Private |
77 | <BLANKLINE> |
78 | + -- |
79 | ... |
80 | - You received this bug notification because you are a member of Ubuntu |
81 | - Team, which is the registrant for Ubuntu. |
82 | - http://bugs.launchpad.dev/bugs/1 |
83 | - <BLANKLINE> |
84 | - Title: |
85 | - Firefox does not support SVG |
86 | ---------------------------------------------------------------------- |
87 | To: test@canonical.com |
88 | ... |
89 | @@ -300,12 +264,7 @@ |
90 | + Another summary |
91 | <BLANKLINE> |
92 | -- |
93 | - You received this bug notification because you are a member of Ubuntu |
94 | - Team, which is the registrant for Ubuntu. |
95 | - http://bugs.launchpad.dev/bugs/1 |
96 | - <BLANKLINE> |
97 | - Title: |
98 | - Firefox does not support SVG |
99 | + ... |
100 | ---------------------------------------------------------------------- |
101 | To: test@canonical.com |
102 | ... |
103 | @@ -445,16 +404,7 @@ |
104 | <BLANKLINE> |
105 | *** This bug is a duplicate of bug 1 *** |
106 | http://bugs.launchpad.dev/bugs/1 |
107 | - <BLANKLINE> |
108 | - a comment. |
109 | - <BLANKLINE> |
110 | - -- |
111 | - You received this bug notification because you are a member of Ubuntu |
112 | - Team, which is the registrant for Ubuntu. |
113 | - http://bugs.launchpad.dev/bugs/16 |
114 | - <BLANKLINE> |
115 | - Title: |
116 | - new bug |
117 | + ... |
118 | ---------------------------------------------------------------------- |
119 | To: test@canonical.com |
120 | From: Sample Person <16@bugs.launchpad.net> |
121 | @@ -463,19 +413,7 @@ |
122 | <BLANKLINE> |
123 | *** This bug is a duplicate of bug 1 *** |
124 | http://bugs.launchpad.dev/bugs/1 |
125 | - <BLANKLINE> |
126 | - a comment. |
127 | - <BLANKLINE> |
128 | - -- |
129 | - You received this bug notification because you are a direct subscriber |
130 | - of the bug. |
131 | - http://bugs.launchpad.dev/bugs/16 |
132 | - <BLANKLINE> |
133 | - Title: |
134 | - new bug |
135 | - <BLANKLINE> |
136 | - To unsubscribe from this bug, go to: |
137 | - http://bugs.launchpad.dev/ubuntu/+bug/16/+subscribe |
138 | + ... |
139 | ---------------------------------------------------------------------- |
140 | |
141 | >>> flush_notifications() |
142 | @@ -585,7 +523,8 @@ |
143 | ... ten_minutes_ago, sample_person, "title", |
144 | ... True, False)) |
145 | |
146 | - >>> notifications = getUtility(IBugNotificationSet).getNotificationsToSend() |
147 | + >>> notifications = getUtility( |
148 | + ... IBugNotificationSet).getNotificationsToSend() |
149 | >>> len(notifications) |
150 | 8 |
151 | |
152 | @@ -660,12 +599,7 @@ |
153 | <BLANKLINE> |
154 | -- = |
155 | <BLANKLINE> |
156 | - You received this bug notification because you are subscribed to |
157 | - mozilla-firefox in Ubuntu. |
158 | - http://bugs.launchpad.dev/bugs/1 |
159 | - <BLANKLINE> |
160 | - Title: |
161 | - Firefox does not support SVG |
162 | + You received this bug notification because... |
163 | INFO Notifying mark@example.com about bug 1. |
164 | ... |
165 | INFO Notifying owner@example.com about bug 1. |
166 | @@ -1051,7 +985,7 @@ |
167 | >>> print_notification(collated_messages['concise@example.com'][0]) |
168 | To: concise@example.com |
169 | ... |
170 | - To unsubscribe from this bug, go to:... |
171 | + To manage notifications about this bug go to:... |
172 | |
173 | Verbose Team Person gets a concise email, even though they belong to a team |
174 | that gets verbose email. |
175 | @@ -1099,8 +1033,8 @@ |
176 | will be automatically wrapped by the BugNotification |
177 | machinery. Ain't technology great? |
178 | <BLANKLINE> |
179 | - To unsubscribe from this bug, go to: |
180 | - http://bugs.launchpad.dev/.../+bug/.../+subscribe |
181 | + To manage notifications about this bug go to: |
182 | + http://bugs.launchpad.dev/.../+bug/.../+subscriptions |
183 | ---------------------------------------------------------------------- |
184 | |
185 | And Concise Team Person does too, even though his team doesn't want them: |
186 | @@ -1128,6 +1062,9 @@ |
187 | This is a long description of the bug, which |
188 | will be automatically wrapped by the BugNotification |
189 | machinery. Ain't technology great? |
190 | + <BLANKLINE> |
191 | + To manage notifications about this bug go to: |
192 | + http://bugs.launchpad.dev/.../+bug/.../+subscriptions |
193 | ---------------------------------------------------------------------- |
194 | |
195 | It's important to note that the bug title and description are wrapped |
196 | @@ -1143,7 +1080,7 @@ |
197 | ... |
198 | 'Bug description:', |
199 | ' This is a long description of the bug, which will be automatically', |
200 | - " wrapped by the BugNotification machinery. Ain't technology great?"] |
201 | + " wrapped by the BugNotification machinery. Ain't technology great?"...] |
202 | |
203 | The title is also wrapped and indented in normal notifications. |
204 | |
205 | @@ -1153,7 +1090,7 @@ |
206 | [... |
207 | 'Title:', |
208 | ' In the beginning, the universe was created. This has made a lot of', |
209 | - ' people very angry and has been widely regarded as a bad move'] |
210 | + ' people very angry and has been widely regarded as a bad move'...] |
211 | |
212 | Self-Generated Bug Notifications |
213 | -------------------------------- |
214 | |
215 | === modified file 'lib/lp/bugs/emailtemplates/bug-notification-verbose.txt' |
216 | --- lib/lp/bugs/emailtemplates/bug-notification-verbose.txt 2011-03-02 16:22:36 +0000 |
217 | +++ lib/lp/bugs/emailtemplates/bug-notification-verbose.txt 2011-05-25 16:14:50 +0000 |
218 | @@ -12,4 +12,4 @@ |
219 | Bug description: |
220 | %(bug_description)s |
221 | |
222 | -%(unsubscribe_notice)s |
223 | +%(subscriptions_message)s |
224 | |
225 | === modified file 'lib/lp/bugs/emailtemplates/bug-notification.txt' |
226 | --- lib/lp/bugs/emailtemplates/bug-notification.txt 2011-03-02 16:22:36 +0000 |
227 | +++ lib/lp/bugs/emailtemplates/bug-notification.txt 2011-05-25 16:14:50 +0000 |
228 | @@ -7,4 +7,4 @@ |
229 | Title: |
230 | %(bug_title)s |
231 | |
232 | -%(unsubscribe_notice)s |
233 | +%(subscriptions_message)s |
234 | |
235 | === modified file 'lib/lp/bugs/scripts/bugnotification.py' |
236 | --- lib/lp/bugs/scripts/bugnotification.py 2011-04-05 22:34:35 +0000 |
237 | +++ lib/lp/bugs/scripts/bugnotification.py 2011-05-25 16:14:50 +0000 |
238 | @@ -193,25 +193,27 @@ |
239 | data['filter descriptions']) |
240 | else: |
241 | filters_text = u"" |
242 | - # XXX deryck 2009-11-17 Bug #484319 |
243 | - # This should be refactored to add a link inside the |
244 | - # code where we build `reason`. However, this will |
245 | - # require some extra work, and this small change now |
246 | - # will ease pain for a lot of unhappy users. |
247 | - if 'direct subscriber' in reason and 'member of' not in reason: |
248 | - unsubscribe_notice = ('To unsubscribe from this bug, go to:\n' |
249 | - '%s/+subscribe' % canonical_url(bug.bugtasks[0])) |
250 | + |
251 | + # In the rare case of a bug with no bugtasks, we can't generate the |
252 | + # subscription management URL so just leave off the subscription |
253 | + # management message entirely. |
254 | + if len(bug.bugtasks): |
255 | + bug_url = canonical_url(bug.bugtasks[0]) |
256 | + notification_url = bug_url + '/+subscriptions' |
257 | + subscriptions_message = ( |
258 | + "To manage notifications about this bug go to:\n%s" |
259 | + % notification_url) |
260 | else: |
261 | - unsubscribe_notice = '' |
262 | + subscriptions_message = '' |
263 | |
264 | data_wrapper = MailWrapper(width=72, indent=' ') |
265 | body_data = { |
266 | 'content': mail_wrapper.format(content), |
267 | 'bug_title': data_wrapper.format(bug.title), |
268 | 'bug_url': canonical_url(bug), |
269 | - 'unsubscribe_notice': unsubscribe_notice, |
270 | 'notification_rationale': mail_wrapper.format(reason), |
271 | 'subscription_filters': filters_text, |
272 | + 'subscriptions_message': subscriptions_message, |
273 | } |
274 | |
275 | # If the person we're sending to receives verbose notifications |
276 | |
277 | === modified file 'lib/lp/bugs/scripts/tests/test_bugnotification.py' |
278 | --- lib/lp/bugs/scripts/tests/test_bugnotification.py 2011-05-12 21:33:10 +0000 |
279 | +++ lib/lp/bugs/scripts/tests/test_bugnotification.py 2011-05-25 16:14:50 +0000 |
280 | @@ -5,6 +5,7 @@ |
281 | __metaclass__ = type |
282 | |
283 | from datetime import datetime, timedelta |
284 | +import re |
285 | import unittest |
286 | |
287 | import pytz |
288 | @@ -20,7 +21,10 @@ |
289 | sqlvalues, |
290 | ) |
291 | from canonical.launchpad.ftests import login |
292 | -from canonical.launchpad.helpers import get_contact_email_addresses |
293 | +from canonical.launchpad.helpers import ( |
294 | + get_contact_email_addresses, |
295 | + get_email_template, |
296 | + ) |
297 | from canonical.launchpad.interfaces.lpstorm import IStore |
298 | from lp.services.messages.interfaces.message import IMessageSet |
299 | from canonical.testing.layers import LaunchpadZopelessLayer |
300 | @@ -929,7 +933,7 @@ |
301 | |
302 | def setUp(self): |
303 | super(TestEmailNotificationsWithFilters, self).setUp() |
304 | - self.bug=self.factory.makeBug() |
305 | + self.bug = self.factory.makeBug() |
306 | subscriber = self.factory.makePerson() |
307 | self.subscription = self.bug.default_bugtask.target.addSubscription( |
308 | subscriber, subscriber) |
309 | @@ -1104,6 +1108,14 @@ |
310 | self.getSubscriptionEmailHeaders()) |
311 | |
312 | |
313 | +def fetch_notifications(subscriber, bug): |
314 | + return IStore(BugNotification).find( |
315 | + BugNotification, |
316 | + BugNotification.id == BugNotificationRecipient.bug_notificationID, |
317 | + BugNotificationRecipient.personID == subscriber.id, |
318 | + BugNotification.bug == bug) |
319 | + |
320 | + |
321 | class TestEmailNotificationsWithFiltersWhenBugCreated(TestCaseWithFactory): |
322 | # See bug 720147. |
323 | |
324 | @@ -1128,11 +1140,7 @@ |
325 | comment=message, owner=self.submitter, |
326 | status=BugTaskStatus.NEW) |
327 | bug = self.product.createBug(params) |
328 | - notification = IStore(BugNotification).find( |
329 | - BugNotification, |
330 | - BugNotification.id==BugNotificationRecipient.bug_notificationID, |
331 | - BugNotificationRecipient.personID == self.subscriber.id, |
332 | - BugNotification.bug == bug).one() |
333 | + notification = fetch_notifications(self.subscriber, bug).one() |
334 | self.assertEqual(notification.message.text_contents, message) |
335 | |
336 | def test_filters_do_not_match_when_bug_is_created(self): |
337 | @@ -1143,9 +1151,41 @@ |
338 | status=BugTaskStatus.TRIAGED, |
339 | importance=BugTaskImportance.HIGH) |
340 | bug = self.product.createBug(params) |
341 | - notifications = IStore(BugNotification).find( |
342 | - BugNotification, |
343 | - BugNotification.id==BugNotificationRecipient.bug_notificationID, |
344 | - BugNotificationRecipient.personID == self.subscriber.id, |
345 | - BugNotification.bug == bug) |
346 | + notifications = fetch_notifications(self.subscriber, bug) |
347 | self.assertTrue(notifications.is_empty()) |
348 | + |
349 | + |
350 | +class TestManageNotificationsMessage(TestCaseWithFactory): |
351 | + |
352 | + layer = LaunchpadZopelessLayer |
353 | + |
354 | + def test_manage_notifications_message_is_included(self): |
355 | + # Set up a subscription to a product. |
356 | + subscriber = self.factory.makePerson() |
357 | + submitter = self.factory.makePerson() |
358 | + product = self.factory.makeProduct( |
359 | + bug_supervisor=submitter) |
360 | + product.addSubscription(subscriber, subscriber) |
361 | + # Create a bug that will match the subscription. |
362 | + bug = product.createBug(CreateBugParams( |
363 | + title=self.factory.getUniqueString(), |
364 | + comment=self.factory.getUniqueString(), |
365 | + owner=submitter)) |
366 | + notification = fetch_notifications(subscriber, bug).one() |
367 | + _, _, (message,) = construct_email_notifications([notification]) |
368 | + payload = message.get_payload() |
369 | + self.assertThat(payload, Contains( |
370 | + 'To manage notifications about this bug go to:\nhttp://')) |
371 | + |
372 | + |
373 | +class TestNotificationSignatureSeparator(TestCase): |
374 | + |
375 | + def test_signature_separator(self): |
376 | + # Email signatures are often separated from the body of a message by a |
377 | + # special separator so user agents can identify the signature for |
378 | + # special treatment (hiding, stripping when replying, colorizing, |
379 | + # etc.). The bug notification messages follow the convention. |
380 | + names = ['bug-notification-verbose.txt', 'bug-notification.txt'] |
381 | + for name in names: |
382 | + template = get_email_template(name, 'bugs') |
383 | + self.assertTrue(re.search('^-- $', template, re.MULTILINE)) |
384 | |
385 | === modified file 'lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt' |
386 | --- lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt 2010-12-23 12:55:53 +0000 |
387 | +++ lib/lp/bugs/stories/bugs/xx-bug-personal-subscriptions.txt 2011-05-25 16:14:50 +0000 |
388 | @@ -1,178 +1,178 @@ |
389 | -= Personal Subscriptions = |
390 | +Personal Subscriptions |
391 | +====================== |
392 | |
393 | Users can subscribe to bugs reported in Launchpad, via the "Subscribe" link |
394 | in the actions portlet. |
395 | |
396 | - >>> from lp.bugs.tests.bug import ( |
397 | - ... print_direct_subscribers, print_also_notified, |
398 | - ... print_subscribers_from_duplicates) |
399 | + >>> from lp.bugs.tests.bug import ( |
400 | + ... print_direct_subscribers, print_also_notified, |
401 | + ... print_subscribers_from_duplicates) |
402 | |
403 | - >>> browser = setupBrowser(auth='Basic foo.bar@canonical.com:test') |
404 | - >>> browser.open('http://bugs.launchpad.dev/firefox/+bug/1') |
405 | - >>> browser.url |
406 | - 'http://bugs.launchpad.dev/firefox/+bug/1' |
407 | + >>> browser = setupBrowser(auth='Basic foo.bar@canonical.com:test') |
408 | + >>> browser.open('http://bugs.launchpad.dev/firefox/+bug/1') |
409 | + >>> browser.url |
410 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
411 | |
412 | >>> browser.getLink('Subscribe').click() |
413 | |
414 | - >>> subscription_widget = browser.getControl(name='field.subscription') |
415 | - >>> subscription_widget.options |
416 | - ['name16'] |
417 | - >>> subscription_widget.value |
418 | - ['name16'] |
419 | + >>> subscription_widget = browser.getControl(name='field.subscription') |
420 | + >>> subscription_widget.options |
421 | + ['name16'] |
422 | + >>> subscription_widget.value |
423 | + ['name16'] |
424 | |
425 | - >>> submit = browser.getControl('Continue') |
426 | + >>> submit = browser.getControl('Continue') |
427 | |
428 | Clicking "Continue" subscribes the user to the bug, and tells the user |
429 | this. |
430 | |
431 | - >>> submit.click() |
432 | - |
433 | - >>> browser.url |
434 | - 'http://bugs.launchpad.dev/firefox/+bug/1' |
435 | - |
436 | - >>> for tag in find_tags_by_class(browser.contents, "informational message"): |
437 | - ... print tag.renderContents() |
438 | - You have been subscribed to this bug. |
439 | + >>> submit.click() |
440 | + |
441 | + >>> browser.url |
442 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
443 | + |
444 | + >>> tags = find_tags_by_class(browser.contents, "informational message") |
445 | + >>> for tag in tags: |
446 | + ... print tag.renderContents() |
447 | + You have been subscribed to this bug. |
448 | |
449 | There's also now a link to unsubscribe the user next to the name. It's a |
450 | relative URL to +subscribe, so it will only work when the portlet is |
451 | in the context of the bug page. |
452 | |
453 | - >>> browser.open( |
454 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
455 | - >>> print_direct_subscribers(browser.contents) |
456 | - Foo Bar (Self-subscribed) (Unsubscribe Foo Bar) |
457 | - Sample Person (Subscribed by Launchpad Janitor) |
458 | - Steve Alexander (Subscribed by Launchpad Janitor) |
459 | - |
460 | - >>> browser.open( |
461 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
462 | - >>> link = browser.getLink(id='unsubscribe-subscriber-16') |
463 | - >>> print link.mech_link.url |
464 | - +subscribe |
465 | - |
466 | - >>> browser.open('http://bugs.launchpad.dev/firefox/+bug/1/') |
467 | - >>> browser.getLink('Unsubscribe').click() |
468 | - >>> print browser.title |
469 | - Bug #1... |
470 | - >>> browser.url |
471 | - 'http://bugs.launchpad.dev/firefox/+bug/1/+subscribe' |
472 | + >>> bug_1 = 'http://bugs.launchpad.dev/bugs/1/' |
473 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
474 | + >>> print_direct_subscribers(browser.contents) |
475 | + Foo Bar (Self-subscribed) (Unsubscribe Foo Bar) |
476 | + Sample Person (Subscribed by Launchpad Janitor) |
477 | + Steve Alexander (Subscribed by Launchpad Janitor) |
478 | + |
479 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
480 | + >>> link = browser.getLink(id='unsubscribe-subscriber-16') |
481 | + >>> print link.mech_link.url |
482 | + +subscribe |
483 | + |
484 | + >>> browser.open(bug_1) |
485 | + >>> browser.getLink('Unsubscribe').click() |
486 | + >>> print browser.title |
487 | + Bug #1... |
488 | + >>> browser.url |
489 | + 'http://bugs.launchpad.dev/firefox/+bug/1/+subscribe' |
490 | |
491 | |
492 | Clicking the "Continue" button from the +subscribe page will unsubscribe |
493 | the user this time, and inform the user. |
494 | |
495 | - >>> subscription_widget.value |
496 | - ['name16'] |
497 | - >>> submit = browser.getControl('Continue') |
498 | - >>> submit.click() |
499 | - |
500 | - >>> browser.url |
501 | - 'http://bugs.launchpad.dev/firefox/+bug/1/' |
502 | - |
503 | - >>> for tag in find_tags_by_class(browser.contents, 'informational message'): |
504 | - ... print tag.renderContents() |
505 | - You have been unsubscribed from bug 1. |
506 | + >>> subscription_widget.value |
507 | + ['name16'] |
508 | + >>> submit = browser.getControl('Continue') |
509 | + >>> submit.click() |
510 | + |
511 | + >>> browser.url |
512 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
513 | + |
514 | + >>> tags = find_tags_by_class(browser.contents, 'informational message') |
515 | + >>> for tag in tags: |
516 | + ... print tag.renderContents() |
517 | + You have been unsubscribed from bug 1. |
518 | |
519 | Users can unsubscribe teams to which they belong. Let's demonstrate by |
520 | first subscribing one of Foo Bar's teams. |
521 | |
522 | - >>> browser.getLink('Subscribe someone else').click() |
523 | - >>> browser.url |
524 | - 'http://bugs.launchpad.dev/firefox/+bug/1/+addsubscriber' |
525 | + >>> browser.getLink('Subscribe someone else').click() |
526 | + >>> browser.url |
527 | + 'http://bugs.launchpad.dev/firefox/+bug/1/+addsubscriber' |
528 | |
529 | - >>> browser.getControl('Person').value = 'launchpad' |
530 | - >>> browser.getControl('Subscribe user').click() |
531 | - >>> browser.url |
532 | - 'http://bugs.launchpad.dev/firefox/+bug/1' |
533 | + >>> browser.getControl('Person').value = 'launchpad' |
534 | + >>> browser.getControl('Subscribe user').click() |
535 | + >>> browser.url |
536 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
537 | |
538 | There's an unsubscribe link next to the team name. |
539 | |
540 | - >>> browser.open( |
541 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
542 | - >>> print_direct_subscribers(browser.contents) |
543 | - Launchpad Developers (Subscribed by Foo Bar) (Unsubscribe Launchpad |
544 | - Developers) |
545 | - Sample Person (Subscribed by Launchpad Janitor) |
546 | - Steve Alexander (Subscribed by Launchpad Janitor) |
547 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
548 | + >>> print_direct_subscribers(browser.contents) |
549 | + Launchpad Developers (Subscribed by Foo Bar) (Unsubscribe Launchpad |
550 | + Developers) |
551 | + Sample Person (Subscribed by Launchpad Janitor) |
552 | + Steve Alexander (Subscribed by Launchpad Janitor) |
553 | |
554 | Clicking either the subscribe link (for subscribing the user to the bug) |
555 | or the unsubscribe link for the team gives us the option of both |
556 | subscribing Foo Bar, and unsubscribing the Launchpad team. |
557 | |
558 | - >>> browser.open( |
559 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
560 | - >>> browser.getLink(id='unsubscribe-subscriber-57').mech_link.url |
561 | - '+subscribe' |
562 | - |
563 | - >>> browser.open('http://bugs.launchpad.dev/firefox/+bug/1') |
564 | - >>> browser.getLink('Subscribe').click() |
565 | - >>> browser.url |
566 | - 'http://bugs.launchpad.dev/firefox/+bug/1/+subscribe' |
567 | - |
568 | - >>> subscription_widget = browser.getControl(name='field.subscription') |
569 | - >>> subscription_widget.options |
570 | - ['name16', 'launchpad'] |
571 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
572 | + >>> browser.getLink(id='unsubscribe-subscriber-57').mech_link.url |
573 | + '+subscribe' |
574 | + |
575 | + >>> browser.open(bug_1) |
576 | + >>> browser.getLink('Subscribe').click() |
577 | + >>> browser.url |
578 | + 'http://bugs.launchpad.dev/firefox/+bug/1/+subscribe' |
579 | + |
580 | + >>> subscription_widget = browser.getControl(name='field.subscription') |
581 | + >>> subscription_widget.options |
582 | + ['name16', 'launchpad'] |
583 | |
584 | Let's unsubscribe the Launchpad team. |
585 | |
586 | - >>> subscription_widget.value = ['launchpad'] |
587 | - >>> browser.getControl('Continue').click() |
588 | - |
589 | - >>> browser.url |
590 | - 'http://bugs.launchpad.dev/firefox/+bug/1' |
591 | - |
592 | - >>> for tag in find_tags_by_class(browser.contents, 'informational message'): |
593 | - ... print tag.renderContents() |
594 | - Launchpad Developers has been unsubscribed from bug 1. |
595 | - |
596 | - >>> browser.open( |
597 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
598 | - >>> print_direct_subscribers(browser.contents) |
599 | - Sample Person (Subscribed by Launchpad Janitor) |
600 | - Steve Alexander (Subscribed by Launchpad Janitor) |
601 | + >>> subscription_widget.value = ['launchpad'] |
602 | + >>> browser.getControl('Continue').click() |
603 | + |
604 | + >>> browser.url |
605 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
606 | + |
607 | + >>> tags = find_tags_by_class(browser.contents, 'informational message') |
608 | + >>> for tag in tags: |
609 | + ... print tag.renderContents() |
610 | + Launchpad Developers has been unsubscribed from bug 1. |
611 | + |
612 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
613 | + >>> print_direct_subscribers(browser.contents) |
614 | + Sample Person (Subscribed by Launchpad Janitor) |
615 | + Steve Alexander (Subscribed by Launchpad Janitor) |
616 | |
617 | On the subscribe page there's a Cancel link as well, that will return |
618 | the browser to the bug page. |
619 | |
620 | - >>> browser.open( |
621 | - ... 'http://bugs.launchpad.dev/firefox/+bug/1/') |
622 | - >>> browser.getLink('Subscribe').click() |
623 | - >>> browser.url |
624 | - 'http://bugs.launchpad.dev/firefox/+bug/1/+subscribe' |
625 | + >>> browser.open(bug_1) |
626 | + >>> browser.getLink('Subscribe').click() |
627 | + >>> browser.url |
628 | + 'http://bugs.launchpad.dev/firefox/+bug/1/+subscribe' |
629 | |
630 | - >>> subscription_widget = browser.getControl(name='field.subscription') |
631 | - >>> subscription_widget.value |
632 | - ['name16'] |
633 | - >>> browser.getLink('Cancel').click() |
634 | - >>> browser.url |
635 | - 'http://bugs.launchpad.dev/firefox/+bug/1/' |
636 | + >>> subscription_widget = browser.getControl(name='field.subscription') |
637 | + >>> subscription_widget.value |
638 | + ['name16'] |
639 | + >>> browser.getLink('Cancel').click() |
640 | + >>> browser.url |
641 | + 'http://bugs.launchpad.dev/firefox/+bug/1' |
642 | |
643 | Foo Bar wasn't subscribed to the bug. |
644 | |
645 | - >>> len(find_tags_by_class(browser.contents, 'informational message')) |
646 | - 0 |
647 | - >>> browser.open( |
648 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
649 | - >>> print_direct_subscribers(browser.contents) |
650 | - Sample Person (Subscribed by Launchpad Janitor) |
651 | - Steve Alexander (Subscribed by Launchpad Janitor) |
652 | + >>> len(find_tags_by_class(browser.contents, 'informational message')) |
653 | + 0 |
654 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
655 | + >>> print_direct_subscribers(browser.contents) |
656 | + Sample Person (Subscribed by Launchpad Janitor) |
657 | + Steve Alexander (Subscribed by Launchpad Janitor) |
658 | |
659 | Subscribers which the current user may unsubscribe (the current user and teams |
660 | -they are a member of) display first in the list, before all other subscriptions. |
661 | - |
662 | - >>> browser.open('http://bugs.launchpad.dev/firefox/+bug/1/+addsubscriber') |
663 | - >>> browser.getControl('Person').value = 'testing-spanish-team' |
664 | - >>> browser.getControl('Subscribe user').click() |
665 | - >>> browser.open( |
666 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
667 | - >>> print_direct_subscribers(browser.contents) |
668 | - testing Spanish team (Subscribed by Foo Bar) |
669 | - (Unsubscribe testing Spanish team) |
670 | - Sample Person (Subscribed by Launchpad Janitor) |
671 | - Steve Alexander (Subscribed by Launchpad Janitor) |
672 | - |
673 | -== Subscriptions and Duplicate Bugs == |
674 | +they are a member of) display first in the list, before all other |
675 | +subscriptions. |
676 | + |
677 | + >>> browser.open( |
678 | + ... 'http://bugs.launchpad.dev/firefox/+bug/1/+addsubscriber') |
679 | + >>> browser.getControl('Person').value = 'testing-spanish-team' |
680 | + >>> browser.getControl('Subscribe user').click() |
681 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
682 | + >>> print_direct_subscribers(browser.contents) |
683 | + testing Spanish team (Subscribed by Foo Bar) |
684 | + (Unsubscribe testing Spanish team) |
685 | + Sample Person (Subscribed by Launchpad Janitor) |
686 | + Steve Alexander (Subscribed by Launchpad Janitor) |
687 | + |
688 | +Subscriptions and Duplicate Bugs |
689 | +-------------------------------- |
690 | |
691 | Because we auto-subscribe users that are directly subscribed to dupes of |
692 | a bug, we give the option to unsubscribe from dupe target bugs. Behind |
693 | @@ -183,13 +183,12 @@ |
694 | |
695 | >>> stevea_browser = setupBrowser( |
696 | ... auth="Basic steve.alexander@ubuntulinux.com:test") |
697 | - >>> stevea_browser.open( |
698 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-dupe-subscribers-content") |
699 | + >>> bug_3 = 'http://launchpad.dev/bugs/3/' |
700 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-dupe-subscribers-content") |
701 | >>> print_subscribers_from_duplicates(stevea_browser.contents) |
702 | From duplicates: |
703 | |
704 | - >>> stevea_browser.open( |
705 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
706 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-subscribers-content") |
707 | >>> print_also_notified(stevea_browser.contents) |
708 | Also notified: |
709 | |
710 | @@ -197,98 +196,92 @@ |
711 | a dupe of bug #3, then Steve gets indirectly subscribed to bug #3, and |
712 | is presented with the Unsubscribe link instead. |
713 | |
714 | - >>> stevea_browser.open( |
715 | - ... "http://launchpad.dev/tomcat/+bug/2/+duplicate") |
716 | - |
717 | - >>> stevea_browser.getControl("Duplicate Of").value = "3" |
718 | - >>> stevea_browser.getControl("Change").click() |
719 | - |
720 | - >>> stevea_browser.open( |
721 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-dupe-subscribers-content") |
722 | - >>> print_subscribers_from_duplicates(stevea_browser.contents) |
723 | - From duplicates: |
724 | - Steve Alexander (Subscribed to bug 2 by Launchpad Janitor) |
725 | - (Unsubscribe Steve Alexander) |
726 | - |
727 | - >>> stevea_browser.getLink(id='unsubscribe-subscriber-11').mech_link.url |
728 | - '+subscribe' |
729 | + >>> bug_2 = 'http://launchpad.dev/tomcat/+bug/2/' |
730 | + >>> stevea_browser.open(bug_2 + "+duplicate") |
731 | + |
732 | + >>> stevea_browser.getControl("Duplicate Of").value = "3" |
733 | + >>> stevea_browser.getControl("Change").click() |
734 | + |
735 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-dupe-subscribers-content") |
736 | + >>> print_subscribers_from_duplicates(stevea_browser.contents) |
737 | + From duplicates: |
738 | + Steve Alexander (Subscribed to bug 2 by Launchpad Janitor) |
739 | + (Unsubscribe Steve Alexander) |
740 | + |
741 | + >>> stevea_browser.getLink(id='unsubscribe-subscriber-11').mech_link.url |
742 | + '+subscribe' |
743 | |
744 | When he chooses to unsubscribe, he will be unsubscribed from bug #2, the |
745 | dupe of bug #3, so he'll no longer get mail from bug #3. |
746 | |
747 | - >>> stevea_browser.open("http://launchpad.dev/bugs/3") |
748 | - >>> stevea_browser.getLink('Unsubscribe').click() |
749 | - >>> stevea_browser.getControl("Continue").click() |
750 | + >>> stevea_browser.open("http://launchpad.dev/bugs/3") |
751 | + >>> stevea_browser.getLink('Unsubscribe').click() |
752 | + >>> stevea_browser.getControl("Continue").click() |
753 | |
754 | # XXX: Brad Bollenbach 2006-09-27 bug=62634: Printing the tag here, |
755 | # instead of tag.string. |
756 | |
757 | - >>> for tag in find_tags_by_class( |
758 | - ... stevea_browser.contents, 'informational message'): |
759 | - ... print tag.renderContents() |
760 | - You have been unsubscribed from bug 3 and 1 duplicate (<a...#2</a>)... |
761 | + >>> for tag in find_tags_by_class( |
762 | + ... stevea_browser.contents, 'informational message'): |
763 | + ... print tag.renderContents() |
764 | + You have been unsubscribed from bug 3 and 1 duplicate (<a...#2</a>)... |
765 | |
766 | (Except for Mark, who has a structural subscription to the target, |
767 | there are no longer any indirect subscribers, because Steve was |
768 | unsubscribed from the dupes and thus is no longer indirectly subscribed |
769 | to bug #3.) |
770 | |
771 | - >>> stevea_browser.open( |
772 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-dupe-subscribers-content") |
773 | - >>> print_subscribers_from_duplicates(stevea_browser.contents) |
774 | - From duplicates: |
775 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-dupe-subscribers-content") |
776 | + >>> print_subscribers_from_duplicates(stevea_browser.contents) |
777 | + From duplicates: |
778 | |
779 | - >>> stevea_browser.open( |
780 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
781 | - >>> print_also_notified(stevea_browser.contents) |
782 | - Also notified: |
783 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-subscribers-content") |
784 | + >>> print_also_notified(stevea_browser.contents) |
785 | + Also notified: |
786 | |
787 | Let's repeat this example, with Steve subscribed to two different dupes, |
788 | to see how the unsubscribe notification changes slightly, because he |
789 | gets unsubscribed from more than one duplicate. |
790 | |
791 | - >>> stevea_browser.open( |
792 | - ... "http://launchpad.dev/firefox/+bug/1/+duplicate") |
793 | - >>> stevea_browser.getControl("Duplicate Of").value = "3" |
794 | - >>> stevea_browser.getControl("Change").click() |
795 | + >>> stevea_browser.open( |
796 | + ... "http://launchpad.dev/firefox/+bug/1/+duplicate") |
797 | + >>> stevea_browser.getControl("Duplicate Of").value = "3" |
798 | + >>> stevea_browser.getControl("Change").click() |
799 | |
800 | (Resubscribe Steve to bug #2, because he was unsubscribed in the |
801 | previous example.) |
802 | |
803 | - >>> stevea_browser.open( |
804 | - ... "http://launchpad.dev/tomcat/+bug/2/+addsubscriber") |
805 | - >>> stevea_browser.getControl('Person').value = 'stevea' |
806 | - >>> stevea_browser.getControl('Subscribe user').click() |
807 | - |
808 | - >>> stevea_browser.open( |
809 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-dupe-subscribers-content") |
810 | - >>> print_subscribers_from_duplicates(stevea_browser.contents) |
811 | - From duplicates: |
812 | - Sample Person (Subscribed ...) |
813 | - Steve Alexander (Subscribed ...) (Unsubscribe Steve Alexander) |
814 | - testing Spanish team (Subscribed to bug 1 by Foo Bar) |
815 | - |
816 | - >>> stevea_browser.open( |
817 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
818 | - >>> print_also_notified(stevea_browser.contents) |
819 | - Also notified: |
820 | - |
821 | - >>> stevea_browser.open("http://launchpad.dev/bugs/3") |
822 | - >>> stevea_browser.getLink("Unsubscribe").click() |
823 | - >>> stevea_browser.getControl("Continue").click() |
824 | - |
825 | - >>> for tag in find_tags_by_class( |
826 | - ... stevea_browser.contents, 'informational message'): |
827 | - ... print tag.renderContents() |
828 | - You have been unsubscribed from bug 3 and 2 duplicates (<a...#1</a>, <a...#2</a>)... |
829 | + >>> stevea_browser.open(bug_2 + "+addsubscriber") |
830 | + >>> stevea_browser.getControl('Person').value = 'stevea' |
831 | + >>> stevea_browser.getControl('Subscribe user').click() |
832 | + |
833 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-dupe-subscribers-content") |
834 | + >>> print_subscribers_from_duplicates(stevea_browser.contents) |
835 | + From duplicates: |
836 | + Sample Person (Subscribed ...) |
837 | + Steve Alexander (Subscribed ...) (Unsubscribe Steve Alexander) |
838 | + testing Spanish team (Subscribed to bug 1 by Foo Bar) |
839 | + |
840 | + >>> stevea_browser.open(bug_3 + "+bug-portlet-subscribers-content") |
841 | + >>> print_also_notified(stevea_browser.contents) |
842 | + Also notified: |
843 | + |
844 | + >>> stevea_browser.open("http://launchpad.dev/bugs/3") |
845 | + >>> stevea_browser.getLink("Unsubscribe").click() |
846 | + >>> stevea_browser.getControl("Continue").click() |
847 | + |
848 | + >>> for tag in find_tags_by_class( |
849 | + ... stevea_browser.contents, 'informational message'): |
850 | + ... print tag.renderContents() |
851 | + You have been unsubscribed from bug 3 and 2 duplicates (<a...#1</a>, <a...#2</a>)... |
852 | |
853 | (Let's undupe bug #1 from bug #3, since it's unneeded for the examples |
854 | that follow.) |
855 | |
856 | - >>> stevea_browser.open( |
857 | - ... "http://launchpad.dev/firefox/+bug/1/+duplicate") |
858 | - >>> stevea_browser.getControl("Duplicate Of").value = "" |
859 | - >>> stevea_browser.getControl("Change").click() |
860 | + >>> stevea_browser.open( |
861 | + ... "http://launchpad.dev/firefox/+bug/1/+duplicate") |
862 | + >>> stevea_browser.getControl("Duplicate Of").value = "" |
863 | + >>> stevea_browser.getControl("Change").click() |
864 | |
865 | This unsubscribe behaviour is team-aware too, so you can unsubscribe |
866 | your teams from a bug, even when the team's subscription comes from a |
867 | @@ -296,76 +289,79 @@ |
868 | bug #2, and notice how bug #3's indirect subscriptions are update to |
869 | include that team. |
870 | |
871 | - >>> foobar_browser = setupBrowser(auth="Basic foo.bar@canonical.com:test") |
872 | - >>> foobar_browser.open("http://launchpad.dev/bugs/2") |
873 | - >>> foobar_browser.getLink('Subscribe someone else').click() |
874 | - >>> foobar_browser.getControl("Person").value = "ubuntu-team" |
875 | - >>> foobar_browser.getControl("Subscribe user").click() |
876 | - |
877 | - >>> foobar_browser.open( |
878 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-dupe-subscribers-content") |
879 | - |
880 | - >>> print_subscribers_from_duplicates(foobar_browser.contents) |
881 | - From duplicates: |
882 | - Ubuntu Team (Subscribed to bug 2 by Foo Bar) (Unsubscribe Ubuntu Team) |
883 | - |
884 | - >>> foobar_browser.open( |
885 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
886 | - |
887 | - >>> print_also_notified(foobar_browser.contents) |
888 | - Also notified: |
889 | + >>> foobar_browser = setupBrowser(auth="Basic foo.bar@canonical.com:test") |
890 | + >>> foobar_browser.open("http://launchpad.dev/bugs/2") |
891 | + >>> foobar_browser.getLink('Subscribe someone else').click() |
892 | + >>> foobar_browser.getControl("Person").value = "ubuntu-team" |
893 | + >>> foobar_browser.getControl("Subscribe user").click() |
894 | + |
895 | + >>> foobar_browser.open(bug_3 + "+bug-portlet-dupe-subscribers-content") |
896 | + |
897 | + >>> print_subscribers_from_duplicates(foobar_browser.contents) |
898 | + From duplicates: |
899 | + Ubuntu Team (Subscribed to bug 2 by Foo Bar) (Unsubscribe Ubuntu Team) |
900 | + |
901 | + >>> foobar_browser.open( |
902 | + ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
903 | + |
904 | + >>> print_also_notified(foobar_browser.contents) |
905 | + Also notified: |
906 | |
907 | The subscribe link for Foo Bar still says "Subscribe", because |
908 | Foo Bar can subscribe himself directly to this bug. For unsubscribing |
909 | the team, the (-) icon can be used. In reality, the two links point to |
910 | the same page, but that is changed when the page is AJAX enabled. |
911 | |
912 | - >>> foobar_browser.open("http://launchpad.dev/bugs/3") |
913 | - >>> foobar_browser.getLink('Subscribe').click() |
914 | + >>> foobar_browser.open("http://launchpad.dev/bugs/3") |
915 | + >>> foobar_browser.getLink('Subscribe').click() |
916 | |
917 | Foo Bar can unsubscribe ubuntu-team, and ubuntu-team will no longer show |
918 | up in the indirect subscriptions. |
919 | |
920 | - >>> subscription_field = foobar_browser.getControl(name="field.subscription") |
921 | - >>> subscription_field.value = ["ubuntu-team"] |
922 | - >>> foobar_browser.getControl("Continue").click() |
923 | + >>> subscription_field = foobar_browser.getControl( |
924 | + ... name="field.subscription") |
925 | + >>> subscription_field.value = ["ubuntu-team"] |
926 | + >>> foobar_browser.getControl("Continue").click() |
927 | |
928 | - >>> for tag in find_tags_by_class( |
929 | - ... foobar_browser.contents, 'informational message'): |
930 | - ... print tag.renderContents() |
931 | - Ubuntu Team has been unsubscribed from bug 3 and 1 duplicate (<a...#2</a>)... |
932 | + >>> for tag in find_tags_by_class( |
933 | + ... foobar_browser.contents, 'informational message'): |
934 | + ... print tag.renderContents() |
935 | + Ubuntu Team has been unsubscribed from bug 3 and 1 duplicate (<a...#2</a>)... |
936 | |
937 | (ubuntu-team is no longer an indirect subscriber.) |
938 | |
939 | - >>> foobar_browser.open( |
940 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-dupe-subscribers-content") |
941 | - >>> print_subscribers_from_duplicates(foobar_browser.contents) |
942 | - From duplicates: |
943 | - |
944 | - >>> foobar_browser.open( |
945 | - ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
946 | - >>> print_also_notified(foobar_browser.contents) |
947 | - Also notified: |
948 | - |
949 | - |
950 | -== Displaying subscribers == |
951 | + >>> foobar_browser.open(bug_3 + "+bug-portlet-dupe-subscribers-content") |
952 | + >>> print_subscribers_from_duplicates(foobar_browser.contents) |
953 | + From duplicates: |
954 | + |
955 | + >>> foobar_browser.open( |
956 | + ... "http://launchpad.dev/bugs/3/+bug-portlet-subscribers-content") |
957 | + >>> print_also_notified(foobar_browser.contents) |
958 | + Also notified: |
959 | + |
960 | + |
961 | +Displaying subscribers |
962 | +---------------------- |
963 | |
964 | The display names of subscribers are escaped in the subscribers list, they are |
965 | -also trimmed to 20 characters, so that they fit alongside the unsubscribe icon. |
966 | - |
967 | - >>> login(ANONYMOUS) |
968 | - >>> abuser = factory.makePerson( |
969 | - ... name='abuser', |
970 | - ... displayname='<script>javascript:alert("YO")</script>') |
971 | - >>> logout() |
972 | - >>> browser.open('http://bugs.launchpad.dev/firefox/+bug/1/+addsubscriber') |
973 | - >>> browser.getControl('Person').value = 'abuser' |
974 | - >>> browser.getControl('Subscribe user').click() |
975 | - >>> browser.open( |
976 | - ... 'http://bugs.launchpad.dev/bugs/1/+bug-portlet-subscribers-content') |
977 | - >>> subscriber_list = find_tag_by_id( |
978 | - ... browser.contents, 'subscribers-direct') |
979 | - >>> for subscriber in subscriber_list.findAll('div'): |
980 | - ... if '~abuser' in subscriber.a['href']: |
981 | - ... print subscriber.a.contents[2].strip() |
982 | - <script>javascrip... |
983 | +also trimmed to 20 characters, so that they fit alongside the unsubscribe |
984 | +icon. |
985 | + |
986 | + >>> login(ANONYMOUS) |
987 | + >>> abuser = factory.makePerson( |
988 | + ... name='abuser', |
989 | + ... displayname='<script>javascript:alert("YO")</script>') |
990 | + >>> logout() |
991 | + >>> browser.open( |
992 | + ... 'http://bugs.launchpad.dev/firefox/+bug/1/+addsubscriber') |
993 | + >>> browser.getControl('Person').value = 'abuser' |
994 | + >>> browser.getControl('Subscribe user').click() |
995 | + >>> bug_1 = 'http://bugs.launchpad.dev/bugs/1/' |
996 | + >>> browser.open(bug_1 + '+bug-portlet-subscribers-content') |
997 | + >>> subscriber_list = find_tag_by_id( |
998 | + ... browser.contents, 'subscribers-direct') |
999 | + >>> for subscriber in subscriber_list.findAll('div'): |
1000 | + ... if '~abuser' in subscriber.a['href']: |
1001 | + ... print subscriber.a.contents[2].strip() |
1002 | + <script>javascrip... |
1003 | + |
1004 | |
1005 | === modified file 'lib/lp/bugs/stories/xx-bugs-statistics-portlet.txt' |
1006 | --- lib/lp/bugs/stories/xx-bugs-statistics-portlet.txt 2011-03-10 17:03:32 +0000 |
1007 | +++ lib/lp/bugs/stories/xx-bugs-statistics-portlet.txt 2011-05-25 16:14:50 +0000 |
1008 | @@ -1,4 +1,5 @@ |
1009 | -= Bug statistics portlet = |
1010 | +Bug statistics portlet |
1011 | +====================== |
1012 | |
1013 | The distribution, project group and project bug listings contain a |
1014 | portlet that shows bug statistics for the target. Each statistic is a |
1015 | @@ -6,7 +7,8 @@ |
1016 | served in a separate request; the request is issued via Javascript and |
1017 | inserted into the page later. |
1018 | |
1019 | -== Distribution == |
1020 | +Distribution |
1021 | +------------ |
1022 | |
1023 | >>> path = 'debian' |
1024 | |
1025 | @@ -77,7 +79,8 @@ |
1026 | http://bugs.launchpad.dev/debian/+cve |
1027 | |
1028 | |
1029 | -== Distribution Series == |
1030 | +Distribution Series |
1031 | +------------------- |
1032 | |
1033 | >>> path = 'debian/woody' |
1034 | |
1035 | @@ -149,7 +152,8 @@ |
1036 | http://bugs.launchpad.dev/debian/woody/+cve |
1037 | |
1038 | |
1039 | -== Distribution Source Package == |
1040 | +Distribution Source Package |
1041 | +--------------------------- |
1042 | |
1043 | >>> path = 'debian/+source/mozilla-firefox' |
1044 | |
1045 | @@ -219,7 +223,8 @@ |
1046 | LinkNotFoundError |
1047 | |
1048 | |
1049 | -== Source Package in Distribution Series == |
1050 | +Source Package in Distribution Series |
1051 | +------------------------------------- |
1052 | |
1053 | >>> path = 'debian/woody/+source/mozilla-firefox' |
1054 | |
1055 | @@ -286,7 +291,8 @@ |
1056 | LinkNotFoundError |
1057 | |
1058 | |
1059 | -== Project group == |
1060 | +Project group |
1061 | +------------- |
1062 | |
1063 | >>> path = 'mozilla' |
1064 | |
1065 | @@ -356,7 +362,8 @@ |
1066 | LinkNotFoundError |
1067 | |
1068 | |
1069 | -== Project == |
1070 | +Project |
1071 | +------- |
1072 | |
1073 | >>> path = 'firefox' |
1074 |
Love this branch, love the cover letter. An MP for the textbooks: good approach with the preparatory cleanups, MP explaining all the right things. And last but not least it's great to see pointlessly brittle doctest checks disappear.
There are still a few nits to pick:
=== modified file 'lib/lp/ bugs/scripts/ bugnotification .py' bugs/scripts/ bugnotification .py 2011-04-05 22:34:35 +0000 bugs/scripts/ bugnotification .py 2011-05-24 16:59:39 +0000
data[ 'filter descriptions'])
filters_ text = u"" url(bug. bugtasks[ 0])) url(bug. bugtasks[ 0]) message = ('To manage notifications about this bug '
--- lib/lp/
+++ lib/lp/
@@ -193,25 +193,26 @@
else:
- # XXX deryck 2009-11-17 Bug #484319
- # This should be refactored to add a link inside the
- # code where we build `reason`. However, this will
- # require some extra work, and this small change now
- # will ease pain for a lot of unhappy users.
- if 'direct subscriber' in reason and 'member of' not in reason:
- unsubscribe_notice = ('To unsubscribe from this bug, go to:\n'
- '%s/+subscribe' % canonical_
+
+ # In the rare case of a bug with no bugtasks, we can't generate the
+ # subscription management URL so just leave off the subscription
+ # management message entirely.
+ if len(bug.bugtasks):
+ bug_url = canonical_
+ notification_url = bug_url + '/+subscriptions'
+ subscriptions_
+ 'go to:\n%s' % notification_url)
While you're here, could you also fix the line break on that last string, and use double quotes so we don't have panic and kitchen fires when an apostrophe shows up?
=== modified file 'lib/lp/ bugs/scripts/ tests/test_ bugnotification .py' bugs/scripts/ tests/test_ bugnotification .py 2011-05-12 21:33:10 +0000 bugs/scripts/ tests/test_ bugnotification .py 2011-05-24 16:59:39 +0000
--- lib/lp/
+++ lib/lp/
@@ -1145,7 +1149,55 @@ createBug( params)
notifications = IStore( BugNotification ).find(
BugNotifi cation, .id==BugNotific ationRecipient. bug_notificatio nID, Recipient. bug_notificatio nID,
BugNotifi cationRecipient .personID == self.subscriber.id,
BugNotifi cation. bug == bug)
self. assertTrue( notifications. is_empty( )) icationsMessage (TestCaseWithFa ctory):
bug = self.product.
- BugNotification
+ BugNotification.id == BugNotification
+
+
+class TestManageNotif
+ # See bug 784575.
Is this bug worth a whole test case though? Surely the test would fit comfortably into some other test case?
+ def setUp(self): eNotificationsM essage, self).setUp() makePerson( ) makePerson( ) makeProduct( self.submitter) addSubscription ( on.bug_ filters[ 0] description = u'Needs triage' statuses = [BugTaskStatus.NEW, BugTaskStatus. INCOMPLE. ..
+ super(TestManag
+ self.subscriber = self.factory.
+ self.submitter = self.factory.
+ self.product = self.factory.
+ bug_supervisor=
+ self.subscription = self.product.
+ self.subscriber, self.subscriber)
+ self.filter = self.subscripti
+ self.filter.
+ self.filter.