← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~bac/launchpad/add-edit-links into lp:launchpad

 

Brad Crittenden has proposed merging lp:~bac/launchpad/add-edit-links into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~bac/launchpad/add-edit-links/+merge/56247

= Summary =

Add structural subscription edit links.

== Proposed fix ==

Add non-JS (blue) links to pages where the new "Subscribe to bug mail"
links are shown.  The links say "Edit bug mail" and point to
"+subscriptions" on the bugs facet.

== Pre-implementation notes ==

None.

== Tests ==

Refactoring of tests made supporting new changes very easy.

bin/test -vvm lp.registry -t test_subscription_links

== Demo and Q/A ==


= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt
  lib/lp/bugs/browser/structuralsubscription.py
  lib/lp/registry/browser/__init__.py
  lib/lp/registry/browser/distribution.py
  lib/lp/registry/templates/productseries-index.pt
  lib/lp/registry/browser/tests/test_subscription_links.py
-- 
https://code.launchpad.net/~bac/launchpad/add-edit-links/+merge/56247
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/launchpad/add-edit-links into lp:launchpad.
=== modified file 'lib/lp/bugs/browser/structuralsubscription.py'
--- lib/lp/bugs/browser/structuralsubscription.py	2011-04-01 20:26:38 +0000
+++ lib/lp/bugs/browser/structuralsubscription.py	2011-04-04 19:06:04 +0000
@@ -375,6 +375,14 @@
         text = 'Subscribe to bug mail'
         return Link('#', text, icon='add', hidden=True, enabled=enabled)
 
+    @enabled_with_permission('launchpad.AnyPerson')
+    def edit_bug_mail(self):
+        sst = self._getSST()
+        enabled = sst.userCanAlterBugSubscription(self.user, self.user)
+        text = 'Edit bug mail'
+        return Link('+subscriptions', text, icon='edit', site='bugs',
+                    enabled=enabled)
+
 
 def expose_structural_subscription_data_to_js(context, request,
                                               user, subscriptions=None):

=== modified file 'lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt'
--- lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt	2011-03-28 03:42:20 +0000
+++ lib/lp/bugs/templates/bugtarget-portlet-bugfilters.pt	2011-04-04 19:06:04 +0000
@@ -14,17 +14,30 @@
       <tal:advanced-structural-subscriptions
          condition="request/features/malone.advanced-structural-subscriptions.enabled">
         <tr class="menu-link-subscribe_to_bug_mail invisible-link"
-            tal:define="subscribe_link menu/subscribe_to_bug_mail|nothing"
-            tal:condition="python: subscribe_link and subscribe_link.enabled">
+            tal:define="link menu/subscribe_to_bug_mail|nothing"
+            tal:condition="python: link and link.enabled">
           <td class="bugs-count" style="padding-top: 3px">
-            <a tal:attributes="href subscribe_link/url">
-              <img tal:attributes="src subscribe_link/icon_url" />
+            <a tal:attributes="href link/url">
+              <img tal:attributes="src link/icon_url" />
             </a>
           </td>
           <td class="bugs-link">
             <a class="js-action"
-               tal:attributes="href subscribe_link/url"
-               tal:content="subscribe_link/escapedtext" />
+               tal:attributes="href link/url"
+               tal:content="link/escapedtext" />
+          </td>
+        </tr>
+        <tr class="menu-link-edit_bug_mail"
+            tal:define="link menu/edit_bug_mail|nothing"
+            tal:condition="python: link and link.enabled">
+          <td class="bugs-count" style="padding-top: 3px">
+            <a tal:attributes="href link/url">
+              <img tal:attributes="src link/icon_url" />
+            </a>
+          </td>
+          <td class="bugs-link">
+            <a tal:attributes="href link/url"
+               tal:content="link/escapedtext" />
           </td>
         </tr>
       </tal:advanced-structural-subscriptions>

=== modified file 'lib/lp/registry/browser/__init__.py'
--- lib/lp/registry/browser/__init__.py	2011-03-29 22:34:04 +0000
+++ lib/lp/registry/browser/__init__.py	2011-04-04 19:06:04 +0000
@@ -77,6 +77,7 @@
         'malone.advanced-structural-subscriptions.enabled')
     if use_advanced_features:
         links.append('subscribe_to_bug_mail')
+        links.append('edit_bug_mail')
     else:
         links.append('subscribe')
 

=== modified file 'lib/lp/registry/browser/distribution.py'
--- lib/lp/registry/browser/distribution.py	2011-03-30 21:38:03 +0000
+++ lib/lp/registry/browser/distribution.py	2011-04-04 19:06:04 +0000
@@ -305,6 +305,7 @@
             'malone.advanced-structural-subscriptions.enabled')
         if use_advanced_features:
             links.append('subscribe_to_bug_mail')
+            links.append('edit_bug_mail')
         return links
 
 

=== modified file 'lib/lp/registry/browser/tests/test_subscription_links.py'
--- lib/lp/registry/browser/tests/test_subscription_links.py	2011-03-30 12:43:00 +0000
+++ lib/lp/registry/browser/tests/test_subscription_links.py	2011-04-04 19:06:04 +0000
@@ -35,7 +35,40 @@
     )
 
 
-class _TestStructSubs(TestCaseWithFactory):
+class _TestResultsMixin:
+    """Mixin to provide common result checking helper methods."""
+
+    @property
+    def old_link(self):
+        return first_tag_by_class(
+            self.contents, 'menu-link-subscribe')
+
+    @property
+    def new_subscribe_link(self):
+        return first_tag_by_class(
+            self.contents, 'menu-link-subscribe_to_bug_mail')
+
+    @property
+    def new_edit_link(self):
+        return first_tag_by_class(
+            self.contents, 'menu-link-edit_bug_mail')
+
+    def assertOldLinkMissing(self):
+        self.assertEqual(None, self.old_link)
+
+    def assertOldLinkPresent(self):
+        self.assertNotEqual(None, self.old_link)
+
+    def assertNewLinksMissing(self):
+        self.assertEqual(None, self.new_subscribe_link)
+        self.assertEqual(None, self.new_edit_link)
+
+    def assertNewLinksPresent(self):
+        self.assertNotEqual(None, self.new_subscribe_link)
+        self.assertNotEqual(None, self.new_edit_link)
+
+
+class _TestStructSubs(TestCaseWithFactory, _TestResultsMixin):
     """Test structural subscriptions base class.
 
     The link to structural subscriptions is controlled by the feature flag
@@ -56,11 +89,6 @@
             with FeatureFixture({self.feature_flag: flag}):
                 view = self.create_view(user)
                 self.contents = view.render()
-                old_link = first_tag_by_class(
-                    self.contents, 'menu-link-subscribe')
-                new_link = first_tag_by_class(
-                    self.contents, 'menu-link-subscribe_to_bug_mail')
-                return old_link, new_link
 
     def create_view(self, user):
         request = LaunchpadTestRequest(
@@ -72,44 +100,44 @@
             request=request, current_request=False)
 
     def test_subscribe_link_feature_flag_off_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.target.owner, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkPresent()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_owner(self):
         # Test the new subscription link.
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.target.owner, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_user(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_user(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, None)
         # The old subscribe link is actually shown to anonymous users but the
         # behavior has changed with the new link.
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, 'on')
         # The subscribe link is not shown to anonymous.
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
 
 class TestProductViewStructSubs(_TestStructSubs):
@@ -201,7 +229,7 @@
     view = '+bugs'
 
 
-class TestDistroViewStructSubs(BrowserTestCase):
+class TestDistroViewStructSubs(BrowserTestCase, _TestResultsMixin):
     """Test structural subscriptions on the distribution view.
 
     Distributions are special.  They are IStructuralSubscriptionTargets but
@@ -235,38 +263,38 @@
                     no_login=no_login,
                     user=logged_in_user)
                 self.contents = browser.contents
-                soup = BeautifulSoup(self.contents)
-                href = canonical_url(
-                    self.target, rootsite=self.rootsite,
-                    view_name='+subscribe')
-                old_link = soup.find('a', href=href)
-                new_link = first_tag_by_class(
-                    self.contents, 'menu-link-subscribe_to_bug_mail')
-                return old_link, new_link
+
+    @property
+    def old_link(self):
+        href = canonical_url(
+            self.target, rootsite=self.rootsite,
+            view_name='+subscribe')
+        soup = BeautifulSoup(self.contents)
+        return soup.find('a', href=href)
 
     def test_subscribe_link_feature_flag_off_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.target.owner, None)
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.target.owner, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_user(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_user_no_bug_super(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_on_user_with_bug_super(self):
         with celebrity_logged_in('admin'):
@@ -274,57 +302,57 @@
             supervisor = self.factory.makePerson()
             self.target.setBugSupervisor(
                 supervisor, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_off_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, None)
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, 'on')
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_off_bug_super(self):
         with celebrity_logged_in('admin'):
             admin = getUtility(ILaunchBag).user
             self.target.setBugSupervisor(
                 self.regular_user, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_bug_super(self):
         with celebrity_logged_in('admin'):
             admin = getUtility(ILaunchBag).user
             self.target.setBugSupervisor(
                 self.regular_user, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_admin(self):
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, None)
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_admin(self):
         from lp.testing.sampledata import ADMIN_EMAIL
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
 
 class TestDistroBugsStructSubs(TestDistroViewStructSubs):
@@ -334,28 +362,28 @@
     view = '+bugs-index'
 
     def test_subscribe_link_feature_flag_off_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.target.owner, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.target.owner, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_user(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_user_no_bug_super(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_on_user_with_bug_super(self):
         with celebrity_logged_in('admin'):
@@ -363,57 +391,57 @@
             supervisor = self.factory.makePerson()
             self.target.setBugSupervisor(
                 supervisor, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_off_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, 'on')
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_off_bug_super(self):
         with celebrity_logged_in('admin'):
             admin = getUtility(ILaunchBag).user
             self.target.setBugSupervisor(
                 self.regular_user, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_bug_super(self):
         with celebrity_logged_in('admin'):
             admin = getUtility(ILaunchBag).user
             self.target.setBugSupervisor(
                 self.regular_user, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_admin(self):
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_admin(self):
         from lp.testing.sampledata import ADMIN_EMAIL
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
 
 class TestDistroMilestoneViewStructSubs(TestDistroViewStructSubs):
@@ -425,28 +453,28 @@
         self.target = self.factory.makeMilestone(distribution=self.distro)
 
     def test_subscribe_link_feature_flag_off_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.distro.owner, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.distro.owner, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_user(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_user_no_bug_super(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_on_user_with_bug_super(self):
         with celebrity_logged_in('admin'):
@@ -454,57 +482,57 @@
             supervisor = self.factory.makePerson()
             self.distro.setBugSupervisor(
                 supervisor, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, 'on')
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_off_bug_super(self):
         with celebrity_logged_in('admin'):
             admin = getUtility(ILaunchBag).user
             self.distro.setBugSupervisor(
                 self.regular_user, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_bug_super(self):
         with celebrity_logged_in('admin'):
             admin = getUtility(ILaunchBag).user
             self.distro.setBugSupervisor(
                 self.regular_user, admin)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_admin(self):
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_admin(self):
         from lp.testing.sampledata import ADMIN_EMAIL
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
 
 class TestProductMilestoneViewStructSubs(TestDistroViewStructSubs):
@@ -519,22 +547,22 @@
         self.target = self.factory.makeMilestone(product=self.product)
 
     def test_subscribe_link_feature_flag_off_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.product.owner, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_owner(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.product.owner, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
     def test_subscribe_link_feature_flag_off_user(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             self.regular_user, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     # There are no special bug supervisor rules for products.
     test_subscribe_link_feature_flag_on_user_no_bug_super = None
@@ -543,31 +571,31 @@
     test_subscribe_link_feature_flag_on_bug_super = None
 
     def test_subscribe_link_feature_flag_off_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_anonymous(self):
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             ANONYMOUS, 'on')
-        self.assertEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_off_admin(self):
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, None)
-        self.assertNotEqual(None, old_link)
-        self.assertEqual(None, new_link)
+        self.assertNotEqual(None, self.old_link)
+        self.assertNewLinksMissing()
 
     def test_subscribe_link_feature_flag_on_admin(self):
         from lp.testing.sampledata import ADMIN_EMAIL
         admin = getUtility(IPersonSet).getByEmail(ADMIN_EMAIL)
-        old_link, new_link = self._create_scenario(
+        self._create_scenario(
             admin, 'on')
-        self.assertEqual(None, old_link)
-        self.assertNotEqual(None, new_link)
+        self.assertOldLinkMissing()
+        self.assertNewLinksPresent()
 
 
 class TestProductSeriesMilestoneViewStructSubs(

=== modified file 'lib/lp/registry/templates/productseries-index.pt'
--- lib/lp/registry/templates/productseries-index.pt	2011-03-29 22:34:04 +0000
+++ lib/lp/registry/templates/productseries-index.pt	2011-04-04 19:06:04 +0000
@@ -211,6 +211,9 @@
             <li tal:condition="overview_menu/subscribe_to_bug_mail/enabled|nothing">
               <a tal:replace="structure overview_menu/subscribe_to_bug_mail/fmt:link" />
             </li>
+            <li tal:condition="overview_menu/edit_bug_mail/enabled|nothing">
+              <a tal:replace="structure overview_menu/edit_bug_mail/fmt:link" />
+            </li>
           </tal:advanced-structural-subscriptions>
           <tal:not-advanced-structural-subscriptions
              condition="not: feature_flag">