Merge lp:~intellectronica/launchpad/bugmail-ui-fixes into lp:launchpad

Proposed by Eleanor Berger
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~intellectronica/launchpad/bugmail-ui-fixes
Merge into: lp:launchpad
Diff against target: 390 lines
10 files modified
lib/canonical/launchpad/browser/structuralsubscription.py (+30/-1)
lib/canonical/launchpad/database/structuralsubscription.py (+11/-0)
lib/canonical/launchpad/interfaces/structuralsubscription.py (+3/-0)
lib/lp/registry/browser/distribution.py (+2/-5)
lib/lp/registry/browser/distroseries.py (+5/-10)
lib/lp/registry/browser/milestone.py (+2/-6)
lib/lp/registry/browser/product.py (+3/-10)
lib/lp/registry/browser/productseries.py (+5/-12)
lib/lp/registry/configure.zcml (+14/-7)
lib/lp/registry/model/milestone.py (+4/-0)
To merge this branch: bzr merge lp:~intellectronica/launchpad/bugmail-ui-fixes
Reviewer Review Type Date Requested Status
Gavin Panella (community) code Approve
Martin Albisetti (community) ui Approve
Michael Nelson (community) ui Approve
Canonical Launchpad Engineering code ui Pending
Review via email: mp+13067@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Eleanor Berger (intellectronica) wrote :

This branch makes the menu link for subscribing to bug mail sensitive to the user's existing subsription. If the user is already subscribed (directly, or via one of the teams he's a member of), the link displays the edit icon and offers to edit subscription. If no subscription exists the link offers to subscribe and displays the add icon.

There are no lint warnings related to my changes (the usual lazr stuff is still there).

To test, run bin/test -vv -t xx-milestone-add-and-edit.txt -t xx-distroseries-index.txt -t xx-productseries-index.txt -t xx-productseries-add-and-edit.txt -t xx-bug-subscriptions.txt -t xx-distribution-bugs-page.txt -t xx-distrorelease-bugs-page.txt -t xx-product-bugs-page.txt > test-output.txt

To play with the UI, go to https://bugs.launchpad.dev/jokosher or https://bugs.launchpad.dev/ubuntu or any of the other structural subscription targets and try to subscribe and unsubscribe.

While working on this I realised that the form for editing structural subscriptions does not behave in the expected way, like all other boomerang forms. It doesn't offer a cancel link, and after submitting it displays the form again, instead of returning to the context. I plan to fix that in a future branch.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

> This branch makes the menu link for subscribing to bug mail sensitive to the
> user's existing subsription. If the user is already subscribed (directly, or
> via one of the teams he's a member of), the link displays the edit icon and
> offers to edit subscription. If no subscription exists the link offers to
> subscribe and displays the add icon.

Nice change Tom! That'll make it much easier for people to follow when they want to edit or remove subscriptions. I actually had to revert your changes to see what happens currently because what you've done is so natural.

Two things on that page that are unrelated to your change, but might be nice to look at, here's a screenshot to show them:

http://people.canonical.com/~michaeln/tmp/bug-subscription-empty-portlet.png

1. There seems to be an empty portlet below? It looks like some ajax is meant to load something there - I'm guessing you're already aware and there's probably already a bug about it.

2. Is there any reason why the "Bug tracker: Launchpad, Bug supervisor:...." section is sitting over on the right like that? It looks exactly like the type of info that is usually a main-area portlet with an h2 heading and a dl (like the Project information at https://edge.launchpad.net/firefox ). Let me know what you think.

[snip]

>
> While working on this I realised that the form for editing structural
> subscriptions does not behave in the expected way, like all other boomerang
> forms. It doesn't offer a cancel link, and after submitting it displays the
> form again, instead of returning to the context. I plan to fix that in a
> future branch.

Great - A few other things to consider on that page when you get to it (in case you didn't already notice them).

First, the heading/breadcrumbs are currently:

Subscribe to Bugs in Jokosher Audio Editor
Jokosher >> Bugs >> Subscribe to Bugs in Jokosher Audio E...

My preference here would be for:

Subscribe to Bugs in Jokosher Audio Editor
Jokosher >> Bugs >> Subscribe

but I've sent an email out to the dev list about this yesterday, and it seems that the consensus is for:

Subscribe
Jokosher >> Bugs >> Subscribe

If you think that ^^ would be wrong, please voice your opinion on the email list :)

Secondly, that tip about "Managing Launchpad Bugs e-mail really doesn't belong there in the side-bar?

Anyway, they're unrelated to this branch. Great work!

review: Approve (ui)
Revision history for this message
Martin Albisetti (beuno) wrote :

Nothing to add!

review: Approve (ui)
Revision history for this message
Gavin Panella (allenap) wrote :

<allenap> intellectronica: I really like your bugmail-ui-fixes branch :)
<allenap> intellectronica: Two questions.
<allenap> intellectronica: Line 49, when it does self.context.context, is that because self.context is a view?
<intellectronica> allenap: exactly. context can be either the target itself or a view
<allenap> intellectronica: Could you add a comment to the else: clause to say that?
<intellectronica> allenap: sure, that's a good idea
<allenap> intellectronica: Question the second. The zcml. Is there an common interface where you can declare the permissions for userHasBugSubscriptions, rather than doing it 7 times?
<intellectronica> allenap: i wish. but no, that's not possible because of the stupid way in which zcml handles the interaction between permissions specified by interface and byb attributes
<allenap> intellectronica: Okay. r=me :)
<intellectronica> allenap: thanks!

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/canonical/launchpad/browser/structuralsubscription.py'
--- lib/canonical/launchpad/browser/structuralsubscription.py 2009-09-17 17:12:58 +0000
+++ lib/canonical/launchpad/browser/structuralsubscription.py 2009-10-22 09:45:25 +0000
@@ -4,6 +4,7 @@
4__metaclass__ = type4__metaclass__ = type
55
6__all__ = [6__all__ = [
7 'StructuralSubscriptionMenuMixin',
7 'StructuralSubscriptionTargetTraversalMixin',8 'StructuralSubscriptionTargetTraversalMixin',
8 'StructuralSubscriptionView',9 'StructuralSubscriptionView',
9 ]10 ]
@@ -19,13 +20,15 @@
19from canonical.launchpad.interfaces import (20from canonical.launchpad.interfaces import (
20 BugNotificationLevel, IDistributionSourcePackage,21 BugNotificationLevel, IDistributionSourcePackage,
21 IStructuralSubscriptionForm)22 IStructuralSubscriptionForm)
23from canonical.launchpad.interfaces.structuralsubscription import (
24 IStructuralSubscriptionTarget)
22from lp.registry.interfaces.person import IPersonSet25from lp.registry.interfaces.person import IPersonSet
23from canonical.launchpad.webapp import (26from canonical.launchpad.webapp import (
24 LaunchpadFormView, action, canonical_url, custom_widget, stepthrough)27 LaunchpadFormView, action, canonical_url, custom_widget, stepthrough)
25from canonical.launchpad.webapp.authorization import check_permission28from canonical.launchpad.webapp.authorization import check_permission
29from canonical.launchpad.webapp.menu import Link
26from canonical.widgets import LabeledMultiCheckBoxWidget30from canonical.widgets import LabeledMultiCheckBoxWidget
2731
28
29class StructuralSubscriptionView(LaunchpadFormView):32class StructuralSubscriptionView(LaunchpadFormView):
30 """View class for structural subscriptions."""33 """View class for structural subscriptions."""
3134
@@ -277,3 +280,29 @@
277 """Traverses +subscription portions of URLs."""280 """Traverses +subscription portions of URLs."""
278 person = getUtility(IPersonSet).getByName(name)281 person = getUtility(IPersonSet).getByName(name)
279 return self.context.getSubscription(person)282 return self.context.getSubscription(person)
283
284
285class StructuralSubscriptionMenuMixin:
286 """Mix-in class providing the subscription add/edit menu link."""
287
288 def subscribe(self):
289 """The subscribe menu link.
290
291 If the user, or any of the teams he's a member of, already has a
292 subscription to the context, the link offer to edit the subscriptions
293 and displays the edit icon. Otherwise, the link offers to subscribe
294 and displays the add icon.
295 """
296 if IStructuralSubscriptionTarget.providedBy(self.context):
297 sst = self.context
298 else:
299 # self.context is a view, and the target is its context
300 sst = self.context.context
301
302 if sst.userHasBugSubscriptions(self.user):
303 text = 'Edit bug mail subscription'
304 icon = 'edit'
305 else:
306 text = 'Subscribe to bug mail'
307 icon = 'add'
308 return Link('+subscribe', text, icon=icon)
280309
=== modified file 'lib/canonical/launchpad/database/structuralsubscription.py'
--- lib/canonical/launchpad/database/structuralsubscription.py 2009-08-25 12:04:58 +0000
+++ lib/canonical/launchpad/database/structuralsubscription.py 2009-10-22 09:45:25 +0000
@@ -326,3 +326,14 @@
326 else:326 else:
327 raise AssertionError(327 raise AssertionError(
328 '%s is not a valid structural subscription target.', self)328 '%s is not a valid structural subscription target.', self)
329
330 def userHasBugSubscriptions(self, user):
331 """See `IStructuralSubscriptionTarget`."""
332 bug_subscriptions = self.getSubscriptions(
333 min_bug_notification_level=BugNotificationLevel.METADATA)
334 for subscription in bug_subscriptions:
335 if (subscription.subscriber == user or
336 user.inTeam(subscription.subscriber)):
337 # The user has a bug subscription
338 return True
339 return False
329340
=== modified file 'lib/canonical/launchpad/interfaces/structuralsubscription.py'
--- lib/canonical/launchpad/interfaces/structuralsubscription.py 2009-09-09 14:26:18 +0000
+++ lib/canonical/launchpad/interfaces/structuralsubscription.py 2009-10-22 09:45:25 +0000
@@ -240,6 +240,9 @@
240240
241 target_type_display = Attribute("The type of the target, for display.")241 target_type_display = Attribute("The type of the target, for display.")
242242
243 def userHasBugSubscriptions(user):
244 """Is `user` subscribed, directly or via a team, to bug mail?"""
245
243246
244class IStructuralSubscriptionForm(Interface):247class IStructuralSubscriptionForm(Interface):
245 """Schema for the structural subscription form."""248 """Schema for the structural subscription form."""
246249
=== modified file 'lib/lp/registry/browser/distribution.py'
--- lib/lp/registry/browser/distribution.py 2009-10-15 10:26:57 +0000
+++ lib/lp/registry/browser/distribution.py 2009-10-22 09:45:25 +0000
@@ -76,6 +76,7 @@
76from lp.soyuz.interfaces.publishedpackage import (76from lp.soyuz.interfaces.publishedpackage import (
77 IPublishedPackageSet)77 IPublishedPackageSet)
78from canonical.launchpad.browser.structuralsubscription import (78from canonical.launchpad.browser.structuralsubscription import (
79 StructuralSubscriptionMenuMixin,
79 StructuralSubscriptionTargetTraversalMixin)80 StructuralSubscriptionTargetTraversalMixin)
80from canonical.launchpad.webapp import (81from canonical.launchpad.webapp import (
81 action, ApplicationMenu, canonical_url, ContextMenu, custom_widget,82 action, ApplicationMenu, canonical_url, ContextMenu, custom_widget,
@@ -421,7 +422,7 @@
421 return Link('+addseries', text, icon='add')422 return Link('+addseries', text, icon='add')
422423
423424
424class DistributionBugsMenu(ApplicationMenu):425class DistributionBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
425426
426 usedfor = IDistribution427 usedfor = IDistribution
427 facet = 'bugs'428 facet = 'bugs'
@@ -451,10 +452,6 @@
451 text = 'Report a bug'452 text = 'Report a bug'
452 return Link('+filebug', text, icon='bug')453 return Link('+filebug', text, icon='bug')
453454
454 def subscribe(self):
455 text = 'Subscribe to bug mail'
456 return Link('+subscribe', text, icon='edit')
457
458455
459class DistributionSpecificationsMenu(NavigationMenu,456class DistributionSpecificationsMenu(NavigationMenu,
460 HasSpecificationsMenuMixin):457 HasSpecificationsMenuMixin):
461458
=== modified file 'lib/lp/registry/browser/distroseries.py'
--- lib/lp/registry/browser/distroseries.py 2009-09-25 17:00:20 +0000
+++ lib/lp/registry/browser/distroseries.py 2009-10-22 09:45:25 +0000
@@ -41,6 +41,7 @@
41 IDistroSeriesLanguageSet)41 IDistroSeriesLanguageSet)
42from lp.services.worlddata.interfaces.language import ILanguageSet42from lp.services.worlddata.interfaces.language import ILanguageSet
43from canonical.launchpad.browser.structuralsubscription import (43from canonical.launchpad.browser.structuralsubscription import (
44 StructuralSubscriptionMenuMixin,
44 StructuralSubscriptionTargetTraversalMixin)45 StructuralSubscriptionTargetTraversalMixin)
45from canonical.launchpad.interfaces.launchpad import (46from canonical.launchpad.interfaces.launchpad import (
46 ILaunchBag, NotFoundError)47 ILaunchBag, NotFoundError)
@@ -142,7 +143,8 @@
142 'translations']143 'translations']
143144
144145
145class DistroSeriesOverviewMenu(ApplicationMenu):146class DistroSeriesOverviewMenu(
147 ApplicationMenu, StructuralSubscriptionMenuMixin):
146148
147 usedfor = IDistroSeries149 usedfor = IDistroSeries
148 facet = 'overview'150 facet = 'overview'
@@ -202,12 +204,8 @@
202 text = 'Show uploads'204 text = 'Show uploads'
203 return Link('+queue', text, icon='info')205 return Link('+queue', text, icon='info')
204206
205 def subscribe(self):207
206 text = 'Subscribe to bug mail'208class DistroSeriesBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
207 return Link('+subscribe', text, icon='edit')
208
209
210class DistroSeriesBugsMenu(ApplicationMenu):
211209
212 usedfor = IDistroSeries210 usedfor = IDistroSeries
213 facet = 'bugs'211 facet = 'bugs'
@@ -223,9 +221,6 @@
223 def nominations(self):221 def nominations(self):
224 return Link('+nominations', 'Review nominations', icon='bug')222 return Link('+nominations', 'Review nominations', icon='bug')
225223
226 def subscribe(self):
227 return Link('+subscribe', 'Subscribe to bug mail')
228
229224
230class DistroSeriesSpecificationsMenu(NavigationMenu,225class DistroSeriesSpecificationsMenu(NavigationMenu,
231 HasSpecificationsMenuMixin):226 HasSpecificationsMenuMixin):
232227
=== modified file 'lib/lp/registry/browser/milestone.py'
--- lib/lp/registry/browser/milestone.py 2009-09-22 16:24:23 +0000
+++ lib/lp/registry/browser/milestone.py 2009-10-22 09:45:25 +0000
@@ -33,6 +33,7 @@
33 IMilestone, IMilestoneSet, IProjectMilestone)33 IMilestone, IMilestoneSet, IProjectMilestone)
34from lp.registry.interfaces.product import IProduct34from lp.registry.interfaces.product import IProduct
35from canonical.launchpad.browser.structuralsubscription import (35from canonical.launchpad.browser.structuralsubscription import (
36 StructuralSubscriptionMenuMixin,
36 StructuralSubscriptionTargetTraversalMixin)37 StructuralSubscriptionTargetTraversalMixin)
37from canonical.launchpad.webapp import (38from canonical.launchpad.webapp import (
38 action, canonical_url, custom_widget,39 action, canonical_url, custom_widget,
@@ -58,7 +59,7 @@
58 usedfor = IMilestone59 usedfor = IMilestone
5960
6061
61class MilestoneLinkMixin:62class MilestoneLinkMixin(StructuralSubscriptionMenuMixin):
62 """The menu for this milestone."""63 """The menu for this milestone."""
6364
64 @enabled_with_permission('launchpad.Edit')65 @enabled_with_permission('launchpad.Edit')
@@ -72,11 +73,6 @@
72 return Link(73 return Link(
73 '+edit', text, icon='edit', summary=summary, enabled=enabled)74 '+edit', text, icon='edit', summary=summary, enabled=enabled)
7475
75 def subscribe(self):
76 """The link to subscribe to bug mail."""
77 enabled = not IProjectMilestone.providedBy(self.context)
78 return Link('+subscribe', 'Subscribe to bug mail',
79 icon='edit', enabled=enabled)
8076
81 @enabled_with_permission('launchpad.Edit')77 @enabled_with_permission('launchpad.Edit')
82 def create_release(self):78 def create_release(self):
8379
=== modified file 'lib/lp/registry/browser/product.py'
--- lib/lp/registry/browser/product.py 2009-10-20 16:45:23 +0000
+++ lib/lp/registry/browser/product.py 2009-10-22 09:45:25 +0000
@@ -89,6 +89,7 @@
89from lp.answers.browser.questiontarget import (89from lp.answers.browser.questiontarget import (
90 QuestionTargetFacetMixin, QuestionTargetTraversalMixin)90 QuestionTargetFacetMixin, QuestionTargetTraversalMixin)
91from canonical.launchpad.browser.structuralsubscription import (91from canonical.launchpad.browser.structuralsubscription import (
92 StructuralSubscriptionMenuMixin,
92 StructuralSubscriptionTargetTraversalMixin)93 StructuralSubscriptionTargetTraversalMixin)
93from canonical.launchpad.mail import format_address, simple_sendmail94from canonical.launchpad.mail import format_address, simple_sendmail
94from canonical.launchpad.webapp import (95from canonical.launchpad.webapp import (
@@ -311,7 +312,7 @@
311 return Link('+branchvisibility', text)312 return Link('+branchvisibility', text)
312313
313314
314class ProductEditLinksMixin:315class ProductEditLinksMixin(StructuralSubscriptionMenuMixin):
315 """A mixin class for menus that need Product edit links."""316 """A mixin class for menus that need Product edit links."""
316317
317 @enabled_with_permission('launchpad.Edit')318 @enabled_with_permission('launchpad.Edit')
@@ -339,10 +340,6 @@
339 text = 'Administer'340 text = 'Administer'
340 return Link('+admin', text, icon='edit')341 return Link('+admin', text, icon='edit')
341342
342 def subscribe(self):
343 text = 'Subscribe to bug mail'
344 return Link('+subscribe', text, icon='edit')
345
346343
347class IProductEditMenu(Interface):344class IProductEditMenu(Interface):
348 """A marker interface for the 'Change details' navigation menu."""345 """A marker interface for the 'Change details' navigation menu."""
@@ -431,7 +428,7 @@
431 return Link('+branchvisibility', text, icon='edit')428 return Link('+branchvisibility', text, icon='edit')
432429
433430
434class ProductBugsMenu(ApplicationMenu):431class ProductBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
435432
436 usedfor = IProduct433 usedfor = IProduct
437 facet = 'bugs'434 facet = 'bugs'
@@ -460,10 +457,6 @@
460 text = 'Change security contact'457 text = 'Change security contact'
461 return Link('+securitycontact', text, icon='edit')458 return Link('+securitycontact', text, icon='edit')
462459
463 def subscribe(self):
464 text = 'Subscribe to bug mail'
465 return Link('+subscribe', text, icon='edit')
466
467460
468class ProductSpecificationsMenu(NavigationMenu,461class ProductSpecificationsMenu(NavigationMenu,
469 HasSpecificationsMenuMixin):462 HasSpecificationsMenuMixin):
470463
=== modified file 'lib/lp/registry/browser/productseries.py'
--- lib/lp/registry/browser/productseries.py 2009-10-22 07:23:57 +0000
+++ lib/lp/registry/browser/productseries.py 2009-10-22 09:45:25 +0000
@@ -54,6 +54,7 @@
54from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities54from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
55from lp.registry.browser import StatusCount55from lp.registry.browser import StatusCount
56from canonical.launchpad.browser.structuralsubscription import (56from canonical.launchpad.browser.structuralsubscription import (
57 StructuralSubscriptionMenuMixin,
57 StructuralSubscriptionTargetTraversalMixin)58 StructuralSubscriptionTargetTraversalMixin)
58from lp.translations.interfaces.potemplate import IPOTemplateSet59from lp.translations.interfaces.potemplate import IPOTemplateSet
59from lp.translations.interfaces.productserieslanguage import (60from lp.translations.interfaces.productserieslanguage import (
@@ -148,7 +149,8 @@
148 return Link(link, text, summary=summary)149 return Link(link, text, summary=summary)
149150
150151
151class ProductSeriesOverviewMenu(ApplicationMenu):152class ProductSeriesOverviewMenu(
153 ApplicationMenu, StructuralSubscriptionMenuMixin):
152 """The overview menu."""154 """The overview menu."""
153 usedfor = IProductSeries155 usedfor = IProductSeries
154 facet = 'overview'156 facet = 'overview'
@@ -219,13 +221,8 @@
219 text = 'Download RDF metadata'221 text = 'Download RDF metadata'
220 return Link('+rdf', text, icon='download')222 return Link('+rdf', text, icon='download')
221223
222 def subscribe(self):224
223 """Return a link to subscribe to bug mail."""225class ProductSeriesBugsMenu(ApplicationMenu, StructuralSubscriptionMenuMixin):
224 text = 'Subscribe to bug mail'
225 return Link('+subscribe', text, icon='edit')
226
227
228class ProductSeriesBugsMenu(ApplicationMenu):
229 """The bugs menu."""226 """The bugs menu."""
230 usedfor = IProductSeries227 usedfor = IProductSeries
231 facet = 'bugs'228 facet = 'bugs'
@@ -243,10 +240,6 @@
243 """Return a link to review bugs nominated for this series."""240 """Return a link to review bugs nominated for this series."""
244 return Link('+nominations', 'Review nominations', icon='bug')241 return Link('+nominations', 'Review nominations', icon='bug')
245242
246 def subscribe(self):
247 """Return a link to subscribe to bug mail."""
248 return Link('+subscribe', 'Subscribe to bug mail')
249
250243
251class ProductSeriesSpecificationsMenu(NavigationMenu,244class ProductSeriesSpecificationsMenu(NavigationMenu,
252 HasSpecificationsMenuMixin):245 HasSpecificationsMenuMixin):
253246
=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml 2009-10-20 13:21:44 +0000
+++ lib/lp/registry/configure.zcml 2009-10-22 09:45:25 +0000
@@ -149,7 +149,8 @@
149 getSubscription149 getSubscription
150 getSubscriptions150 getSubscriptions
151 parent_subscription_target151 parent_subscription_target
152 target_type_display"/>152 target_type_display
153 userHasBugSubscriptions"/>
153 <require154 <require
154 permission="launchpad.AnyPerson"155 permission="launchpad.AnyPerson"
155 attributes="156 attributes="
@@ -285,7 +286,8 @@
285 getSubscription286 getSubscription
286 getBugNotificationsRecipients287 getBugNotificationsRecipients
287 parent_subscription_target288 parent_subscription_target
288 target_type_display"/>289 target_type_display
290 userHasBugSubscriptions"/>
289 <require291 <require
290 permission="launchpad.AnyPerson"292 permission="launchpad.AnyPerson"
291 attributes="293 attributes="
@@ -395,7 +397,8 @@
395 target_type_display397 target_type_display
396 official_bug_tags398 official_bug_tags
397 findRelatedArchives399 findRelatedArchives
398 findRelatedArchivePublications"/>400 findRelatedArchivePublications
401 userHasBugSubscriptions"/>
399 <require402 <require
400 permission="launchpad.AnyPerson"403 permission="launchpad.AnyPerson"
401 attributes="404 attributes="
@@ -903,7 +906,8 @@
903 getSubscription906 getSubscription
904 getBugNotificationsRecipients907 getBugNotificationsRecipients
905 parent_subscription_target908 parent_subscription_target
906 target_type_display"/>909 target_type_display
910 userHasBugSubscriptions"/>
907 <require911 <require
908 permission="launchpad.AnyPerson"912 permission="launchpad.AnyPerson"
909 attributes="913 attributes="
@@ -1150,7 +1154,8 @@
1150 getSubscription1154 getSubscription
1151 getBugNotificationsRecipients1155 getBugNotificationsRecipients
1152 parent_subscription_target1156 parent_subscription_target
1153 target_type_display"/>1157 target_type_display
1158 userHasBugSubscriptions"/>
1154 <require1159 <require
1155 permission="launchpad.AnyPerson"1160 permission="launchpad.AnyPerson"
1156 attributes="1161 attributes="
@@ -1297,7 +1302,8 @@
1297 getSubscription1302 getSubscription
1298 getSubscriptions1303 getSubscriptions
1299 parent_subscription_target1304 parent_subscription_target
1300 target_type_display"/>1305 target_type_display
1306 userHasBugSubscriptions"/>
1301 <require1307 <require
1302 permission="launchpad.AnyPerson"1308 permission="launchpad.AnyPerson"
1303 attributes="1309 attributes="
@@ -1407,7 +1413,8 @@
1407 getSubscription1413 getSubscription
1408 getBugNotificationsRecipients1414 getBugNotificationsRecipients
1409 parent_subscription_target1415 parent_subscription_target
1410 target_type_display"/>1416 target_type_display
1417 userHasBugSubscriptions"/>
1411 <require1418 <require
1412 permission="launchpad.AnyPerson"1419 permission="launchpad.AnyPerson"
1413 attributes="1420 attributes="
14141421
=== modified file 'lib/lp/registry/model/milestone.py'
--- lib/lp/registry/model/milestone.py 2009-09-29 18:55:25 +0000
+++ lib/lp/registry/model/milestone.py 2009-10-22 09:45:25 +0000
@@ -301,3 +301,7 @@
301 def official_bug_tags(self):301 def official_bug_tags(self):
302 """See `IHasBugs`."""302 """See `IHasBugs`."""
303 return self.target.official_bug_tags303 return self.target.official_bug_tags
304
305 def userHasBugSubscriptions(self, user):
306 """See `IStructuralSubscriptionTarget`."""
307 return False