1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
Subscriptions View
------------------
XXX: bdmurray 2010-09-24 bug=628411 This story is complete until we publish
the link that leads to the +subscriptions page.
Any user can view the direct subscriptions that a person or team has to
blueprints, branches, bugs, merge proposals and questions.
>>> anon_browser.open('http://launchpad.dev/~ubuntu-team/+subscriptions')
>>> print anon_browser.title
Subscriptions : “Ubuntu Team” team
The user can see that the Ubuntu Team does not have any direct bug
subscriptions.
>>> page_text = extract_text(find_main_content(anon_browser.contents))
>>> "does not have any direct bug subscriptions" in page_text
True
To test bug subscriptions we are going to create two products, Affluenza and
Scofflaw, and a user Webster who will be subscribed to bugs about both of
those.
>>> login('foo.bar@canonical.com')
>>> scofflaw = factory.makeProduct(name='scofflaw')
>>> bugA = factory.makeBug(product=scofflaw,
... title='Word needs more popularity')
>>> affluenza = factory.makeProduct(name='affluenza')
>>> bugB = factory.makeBug(product=affluenza,
... title='A terrible affliction')
>>> subscriber = factory.makePerson(name='webster',
... password='g00dpassword')
>>> subscriptionA = bugA.subscribe(subscriber, subscriber)
>>> subscriptionB = bugB.subscribe(subscriber, subscriber)
>>> logout()
Any user can see Webster's bug subscriptions. The bug subscriptions table
includes the bug number, title and location.
>>> anon_browser.open('http://launchpad.dev/~webster/+subscriptions')
>>> print extract_text(find_tag_by_id(
... anon_browser.contents, 'bug_subscriptions'))
Summary
In
...
Word needs more popularity
Scofflaw
...
A terrible affliction
Affluenza
The bug subscriptions table also includes an unsubscribe link, if the user has
permission to remove the subscription, for bugs to which the person or team is
subscribed.
Webster can see and manage his direct bug subscriptions using the page too.
He chooses to view the bug about Scofflaw.
>>> login('foo.bar@canonical.com')
>>> subscriber_browser = setupBrowser(
... auth='Basic %s:g00dpassword' %
... subscriber.preferredemail.email)
>>> logout()
>>> subscriber_browser.open(
... 'http://bugs.launchpad.dev/~webster/+subscriptions')
>>> unsub_link = subscriber_browser.getLink(
... id='unsubscribe-subscriber-%s' % subscriber.id)
>>> unsub_link.click()
>>> page_text = extract_text(find_tag_by_id(
... subscriber_browser.contents, 'nonportlets'))
>>> "unsubscribe me from this bug" in page_text
True
After viewing the +subscribe page Webster decides that he still wants to be
subscribed to the bug. He clicks cancel which takes him back to his
+subscription page.
>>> cancel_link = subscriber_browser.getLink('Cancel')
>>> cancel_link.click()
>>> print subscriber_browser.title
Subscriptions : Webster
He chooses to unsubscribe from the bug about Affluenza.
>>> subscriber_browser.getLink(url='/affluenza/+bug/%s/+subscribe'
... % bugB.id).click()
>>> subscriber_browser.getControl(
... "unsubscribe me from this bug").selected = True
>>> subscriber_browser.getControl("Continue").click()
>>> print subscriber_browser.title
Subscriptions : Webster
Webster can see that the bug about Affluenza is no longer listed in his direct
bug subscriptions.
>>> subscriber_browser.open(
... 'http://bugs.launchpad.dev/~webster/+subscriptions')
>>> print extract_text(find_tag_by_id(
... subscriber_browser.contents, 'bug_subscriptions'))
Summary
In
...
Word needs more popularity
Scofflaw
Webster adds a bug subscription for a team, team America, of which he is a
member.
>>> login('foo.bar@canonical.com')
>>> team = factory.makeTeam(name='america')
>>> bugC = factory.makeBug(product=scofflaw,
... title="Word came from a contest")
>>> membership = team.addMember(subscriber, subscriber)
>>> subscriptionC = bugC.subscribe(team, subscriber)
>>> logout()
Webster chooses to review the subscriptions for his team America.
>>> subscriber_browser.open(
... 'https://bugs.launchpad.dev/~america/+subscriptions')
>>> print subscriber_browser.title
Subscriptions : “America” team
>>> print extract_text(find_tag_by_id(
... subscriber_browser.contents, 'bug_subscriptions'))
Summary
In
...
Word came from a contest
Scofflaw
Webster now chooses to unsubscribe team America from the bug about Scofflaw.
>>> subscriber_browser.getLink(id='unsubscribe-subscriber-%s' %
... team.id).click()
>>> print extract_text(find_tags_by_class(
... subscriber_browser.contents, 'value')[0])
subscribe me to this bug, or
unsubscribe America from this bug.
>>> subscriber_browser.getControl(
... 'unsubscribe America from this bug').selected = True
>>> subscriber_browser.getControl('Continue').click()
>>> subscriber_browser.open(
... 'https://launchpad.dev/~america/+subscriptions')
>>> page_text = extract_text(
... find_main_content(subscriber_browser.contents))
>>> "does not have any direct bug subscriptions" in page_text
True
Structural subscriptions
========================
Leading from the subscriptions view is an overview page of all
structural subscriptions.
>>> admin_browser.open("http://launchpad.dev/people/+me/+subscriptions")
>>> admin_browser.getLink("Structural subscriptions").click()
>>> admin_browser.url
'http://launchpad.dev/~name16/+structural-subscriptions'
>>> admin_browser.title
'Structural subscriptions : Foo Bar'
The structures to which the user is subscribed are displayed in a
list. The title of the structure links to the structure itself, and is
followed by a link to edit the subscription.
>>> subscriptions = find_tag_by_id(
... admin_browser.contents, 'structural-subscriptions')
>>> for subscription in subscriptions.findAll("li"):
... structure_link, modify_link = subscription.findAll("a")[:2]
... print "%s <%s>" % (
... extract_text(structure_link), structure_link.get("href"))
... print "--> %s" % modify_link.get("href")
mozilla-firefox in Ubuntu </ubuntu/+source/mozilla-firefox>
--> /ubuntu/+source/mozilla-firefox/+subscribe
pmount in Ubuntu </ubuntu/+source/pmount>
--> /ubuntu/+source/pmount/+subscribe
The links to modify subscriptions are only shown when the user has
permission to modify those subscriptions.
>>> subscriber_browser.open(
... "http://launchpad.dev/~name16/+structural-subscriptions")
>>> subscriptions = find_tag_by_id(
... subscriber_browser.contents, 'structural-subscriptions')
>>> for subscription in subscriptions.findAll("li"):
... structure_link = subscription.find("a")
... print "%s <%s>" % (
... extract_text(structure_link), structure_link.get("href"))
mozilla-firefox in Ubuntu </ubuntu/+source/mozilla-firefox>
pmount in Ubuntu </ubuntu/+source/pmount>
The structural subscriptions page links back to the direct
subscriptions page.
>>> admin_browser.getLink("Direct subscriptions").url
'http://launchpad.dev/~name16/+subscriptions'
A simple explanatory message is shown when the user doesn't have any
structural subscriptions.
>>> subscriber_browser.open(
... "http://launchpad.dev/people/+me/+structural-subscriptions")
>>> print extract_text(find_tag_by_id(
... subscriber_browser.contents, "structural-subscriptions"))
Webster does not have any structural subscriptions.
Creating Bug Filters
~~~~~~~~~~~~~~~~~~~~
Every structural subscription also has a link to create a new bug
subscription filter.
>>> import re
>>> def show_create_links(browser):
... subscriptions = find_tag_by_id(
... browser.contents, 'structural-subscriptions')
... for subscription in subscriptions.findAll("li"):
... structure_link = subscription.find("a")
... print extract_text(structure_link)
... create_text = subscription.find(text=re.compile("Create"))
... if create_text is None:
... print "* No create link."
... else:
... print "* %s --> %s" % (
... create_text.strip(),
... create_text.parent.get("href"))
>>> admin_browser.open(
... "http://launchpad.dev/people/+me/+structural-subscriptions")
>>> show_create_links(admin_browser)
mozilla-firefox in Ubuntu
* Create a new filter --> /ubuntu/.../name16/+new-filter
pmount in Ubuntu
* Create a new filter --> /ubuntu/.../name16/+new-filter
If the user does not have the necessary rights to create new bug
filters the "Create" link is not shown.
>>> subscriber_browser.open(
... "http://launchpad.dev/~name16/+structural-subscriptions")
>>> show_create_links(subscriber_browser)
mozilla-firefox in Ubuntu
* No create link.
pmount in Ubuntu
* No create link.
Subscriptions with Bug Filters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Products for which a subscription exists bug for which there are no
filters are shown with a message stating that there is no filtering.
>>> from lp.testing import celebrity_logged_in, person_logged_in
>>> with celebrity_logged_in("admin"):
... nigel = factory.makePerson(
... name="nigel", displayname="Nigel",
... password="g00dpassword")
>>> with person_logged_in(nigel):
... nigel_subscription = scofflaw.addBugSubscription(nigel, nigel)
... nigel_browser = setupBrowser(
... auth='Basic %s:g00dpassword' % nigel.preferredemail.email)
>>> def show_nigels_subscriptions():
... nigel_browser.open(
... "http://launchpad.dev/people/"
... "+me/+structural-subscriptions")
... subscriptions = find_tag_by_id(
... nigel_browser.contents, 'structural-subscriptions')
... for subscription in subscriptions.findAll("li"):
... print extract_text(subscription.p)
... if subscription.dl is not None:
... print extract_text(subscription.dl)
>>> show_nigels_subscriptions()
Bug mail for Nigel about Scofflaw is filtered;
...
This filter allows all mail through.
There are no filter conditions!
(edit)
If a bug mail filter exists for a structural subscription it is
displayed immediately after the subscription.
>>> with person_logged_in(nigel):
... nigel_bug_filter1 = nigel_subscription.bug_filters.one()
... nigel_bug_filter1.description = u"First"
... nigel_bug_filter1.tags = [u"foo"]
>>> show_nigels_subscriptions()
Bug mail for Nigel about Scofflaw is filtered; it will be sent
only if it matches the following filter:
“First” allows mail through when:
the bug is tagged with foo
(edit)
Multiple filters will be shown if they exist, with a slightly modified
message.
>>> with person_logged_in(nigel):
... nigel_bug_filter2 = nigel_subscription.newBugFilter()
... nigel_bug_filter2.description = u"Second"
... nigel_bug_filter2.tags = [u"bar"]
>>> show_nigels_subscriptions()
Bug mail for Nigel about Scofflaw is filtered; it will be sent
only if it matches one or more of the following filters:
“First” allows mail through when:
the bug is tagged with foo
(edit)
“Second” allows mail through when:
the bug is tagged with bar
(edit)
|