← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/mailing-list-name-field into lp:launchpad

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/mailing-list-name-field into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~sinzui/launchpad/mailing-list-name-field/+merge/90479

iDo not imply a team can be renamed when it has a mailing list.

    Launchpad bug: https://bugs.launchpad.net/bugs/889496
    Pre-implementation: myself

The field to rename was shown implying I could do the rename. The form
did not check that there was an mailing list. I was confused actually,
because the team page did not show an list. This list was being created
:(.

This is not an issue with the +edit page. I was using the +review page.
I think the two view need to share some code.

    * +review implies I can change the name of a user with an active PPA...
      PersonRenameFormMixin. This is broken for users and teams.
    * There are two options. A. subclass TeamEditView or
      create a new class using TeamFormMixin, PersonRenameFormMixin.

--------------------------------------------------------------------

RULES

    * Extract the rename tests from TestPersonEditView to a mixin.
    * Add a testcase for PersonAdministerView that used the new mixin.
    * Update PersonAdministerView to extend PersonRenameFormMixin
    * Extract the rename tests from TestTeamEditView to a mixin.
    * Add a test for for TeamAdministerView that uses the mixin.
    * Create TeamAdministerView from PersonAdministerViewthat does
      not have standing.


QA

    * Visit https://qastaging.launchpad.net/~test234/+review
    * Verify that the name field is not editable.
    * Visit https://qastaging.launchpad.net/~sinzui/+review
    * Verify that the name field is not editable.


LINT

    lib/lp/registry/browser/configure.zcml
    lib/lp/registry/browser/person.py
    lib/lp/registry/browser/team.py
    lib/lp/registry/browser/tests/test_person_view.py
    lib/lp/registry/browser/tests/test_team.py



TEST

    ./bin/test -vv -t TestPersonEditView -t PersonAdministerViewTestCase \
        lp.registry.browser.tests.test_person_view
    ./bin/test -vvc -t TestTeamEditView -t TeamAdminisiterViewTestCase \
        lp.registry.browser.tests.test_team


IMPLEMENTATION

Updated PersonAdministerView to use PersonRenameFormMixin. Extracted the
common rename tests to a mixin and used it in both the edit and
administer test cases. I had to move PersonRenameFormMixin which inflated
the diff. I modernised the setup of the mixing tests. I added tests about
which fields are visible to admins and registry_experts because I did not
see the rules verified in other browser tests.
    lib/lp/registry/browser/person.py
    lib/lp/registry/browser/tests/test_person_view.py

Subclassed PersonAdministerView so that I do not see the user standing
fields when looking at a team. Extracted the common rename tests to a mixin
and used it in both the edit and administer test cases.
    lib/lp/registry/browser/configure.zcml
    lib/lp/registry/browser/team.py
    lib/lp/registry/browser/tests/test_team.py
-- 
https://code.launchpad.net/~sinzui/launchpad/mailing-list-name-field/+merge/90479
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/mailing-list-name-field into lp:launchpad.
=== modified file 'lib/lp/registry/browser/configure.zcml'
--- lib/lp/registry/browser/configure.zcml	2012-01-18 16:49:09 +0000
+++ lib/lp/registry/browser/configure.zcml	2012-01-27 16:44:35 +0000
@@ -1152,6 +1152,12 @@
             permission="launchpad.Edit"
             template="../templates/team-edit.pt"/>
         <browser:page
+            name="+review"
+            for="lp.registry.interfaces.person.ITeam"
+            class="lp.registry.browser.team.TeamAdministerView"
+            permission="launchpad.Moderate"
+            template="../templates/person-review.pt"/>
+        <browser:page
             name="+branding"
             for="lp.registry.interfaces.person.ITeam"
             class="lp.registry.browser.team.TeamBrandingView"

=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py	2012-01-25 04:56:50 +0000
+++ lib/lp/registry/browser/person.py	2012-01-27 16:44:35 +0000
@@ -1225,7 +1225,24 @@
         return encodeddata
 
 
-class PersonAdministerView(LaunchpadEditFormView):
+class PersonRenameFormMixin(LaunchpadEditFormView):
+
+    def setUpWidgets(self):
+        """See `LaunchpadViewForm`.
+
+        Renames are prohibited if a person/team has an active PPA or an
+        active mailing list.
+        """
+        reason = self.context.checkRename()
+        if reason:
+            # This makes the field's widget display (i.e. read) only.
+            self.form_fields['name'].for_display = True
+        super(PersonRenameFormMixin, self).setUpWidgets()
+        if reason:
+            self.widgets['name'].hint = reason
+
+
+class PersonAdministerView(PersonRenameFormMixin):
     """Administer an `IPerson`."""
     schema = IPerson
     label = "Review person"
@@ -3475,23 +3492,6 @@
     page_title = label
 
 
-class PersonRenameFormMixin(LaunchpadEditFormView):
-
-    def setUpWidgets(self):
-        """See `LaunchpadViewForm`.
-
-        Renames are prohibited if a person/team has an active PPA or an
-        active mailing list.
-        """
-        reason = self.context.checkRename()
-        if reason:
-            # This makes the field's widget display (i.e. read) only.
-            self.form_fields['name'].for_display = True
-        super(PersonRenameFormMixin, self).setUpWidgets()
-        if reason:
-            self.widgets['name'].hint = reason
-
-
 class PersonEditView(PersonRenameFormMixin, BasePersonEditView):
     """The Person 'Edit' page."""
 

=== modified file 'lib/lp/registry/browser/team.py'
--- lib/lp/registry/browser/team.py	2012-01-25 04:56:50 +0000
+++ lib/lp/registry/browser/team.py	2012-01-27 16:44:35 +0000
@@ -95,6 +95,7 @@
 from lp.registry.browser.objectreassignment import ObjectReassignmentView
 from lp.registry.browser.person import (
     CommonMenuLinks,
+    PersonAdministerView,
     PersonIndexView,
     PersonNavigation,
     PersonRenameFormMixin,
@@ -353,6 +354,12 @@
     cancel_url = next_url
 
 
+class TeamAdministerView(PersonAdministerView):
+    """A view to administer teams on behalf of users."""
+    label = "Review team"
+    default_field_names = ['name', 'displayname']
+
+
 def generateTokenAndValidationEmail(email, team):
     """Send a validation message to the given email."""
     login = getUtility(ILaunchBag).login

=== modified file 'lib/lp/registry/browser/tests/test_person_view.py'
--- lib/lp/registry/browser/tests/test_person_view.py	2012-01-20 15:42:44 +0000
+++ lib/lp/registry/browser/tests/test_person_view.py	2012-01-27 16:44:35 +0000
@@ -21,10 +21,7 @@
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.bugs.model.bugtask import BugTask
 from lp.buildmaster.enums import BuildStatus
-from lp.registry.browser.person import (
-    PersonEditView,
-    PersonView,
-    )
+from lp.registry.browser.person import PersonView
 from lp.registry.browser.team import TeamInvitationView
 from lp.registry.interfaces.karma import IKarmaCacheManager
 from lp.registry.interfaces.person import (
@@ -57,6 +54,7 @@
 from lp.testing import (
     ANONYMOUS,
     login,
+    login_celebrity,
     login_person,
     person_logged_in,
     StormStatementRecorder,
@@ -136,7 +134,7 @@
     def test_private_superteams_anonymous(self):
         # If the viewer is anonymous, the portlet is not shown.
         team = self.createTeams()
-        viewer = self.factory.makePerson()
+        self.factory.makePerson()
         view = create_initialized_view(
             team, '+index', server_url=canonical_url(team), path_info='')
         html = view()
@@ -324,18 +322,7 @@
         self.failUnless(person_view.should_show_ppa_section)
 
 
-class TestPersonEditView(TestCaseWithFactory):
-
-    layer = LaunchpadFunctionalLayer
-
-    def setUp(self):
-        TestCaseWithFactory.setUp(self)
-        self.valid_email_address = self.factory.getUniqueEmailAddress()
-        self.person = self.factory.makePerson(email=self.valid_email_address)
-        login_person(self.person)
-        self.ppa = self.factory.makeArchive(owner=self.person)
-        self.view = PersonEditView(
-            self.person, LaunchpadTestRequest())
+class TestPersonRenameFormMixin:
 
     def test_can_rename_with_empty_PPA(self):
         # If a PPA exists but has no packages, we can rename the
@@ -380,6 +367,19 @@
         self.view.initialize()
         self.assertFalse(self.view.form_fields['name'].for_display)
 
+
+class TestPersonEditView(TestPersonRenameFormMixin, TestCaseWithFactory):
+
+    layer = LaunchpadFunctionalLayer
+
+    def setUp(self):
+        super(TestPersonEditView, self).setUp()
+        self.valid_email_address = self.factory.getUniqueEmailAddress()
+        self.person = self.factory.makePerson(email=self.valid_email_address)
+        login_person(self.person)
+        self.ppa = self.factory.makeArchive(owner=self.person)
+        self.view = create_initialized_view(self.person, '+edit')
+
     def test_add_email_good_data(self):
         email_address = self.factory.getUniqueEmailAddress()
         form = {
@@ -423,6 +423,34 @@
         self.assertEqual(expected_msg, error_msg)
 
 
+class PersonAdministerViewTestCase(TestPersonRenameFormMixin,
+                                   TestCaseWithFactory):
+    layer = LaunchpadFunctionalLayer
+
+    def setUp(self):
+        super(PersonAdministerViewTestCase, self).setUp()
+        self.person = self.factory.makePerson()
+        login_celebrity('admin')
+        self.ppa = self.factory.makeArchive(owner=self.person)
+        self.view = create_initialized_view(self.person, '+review')
+
+    def test_init_admin(self):
+        # An admin sees all the fields.
+        self.assertEqual('Review person', self.view.label)
+        self.assertEqual(
+            ['name', 'displayname', 'personal_standing',
+             'personal_standing_reason'],
+            self.view.field_names)
+
+    def test_init_registry_expert(self):
+        # Registry experts do no see the the displayname field.
+        login_celebrity('registry_experts')
+        self.view.setUpFields()
+        self.assertEqual(
+            ['name', 'personal_standing', 'personal_standing_reason'],
+            self.view.field_names)
+
+
 class TestTeamCreationView(TestCaseWithFactory):
 
     layer = DatabaseFunctionalLayer

=== modified file 'lib/lp/registry/browser/tests/test_team.py'
--- lib/lp/registry/browser/tests/test_team.py	2012-01-23 18:15:34 +0000
+++ lib/lp/registry/browser/tests/test_team.py	2012-01-27 16:44:35 +0000
@@ -30,6 +30,7 @@
 from lp.services.webapp.publisher import canonical_url
 from lp.soyuz.enums import ArchiveStatus
 from lp.testing import (
+    login_celebrity,
     login_person,
     person_logged_in,
     TestCaseWithFactory,
@@ -173,9 +174,9 @@
         self.acceptTeam(self.super_team, successful, failed)
 
 
-class TestTeamEditView(TestCaseWithFactory):
+class TestTeamPersonRenameFormMixin:
 
-    layer = LaunchpadFunctionalLayer
+    view_name = None
 
     def test_cannot_rename_team_with_active_ppa(self):
         # A team with an active PPA that contains publications cannot be
@@ -186,7 +187,7 @@
         self.factory.makeSourcePackagePublishingHistory(archive=archive)
         get_property_cache(team).archive = archive
         with person_logged_in(owner):
-            view = create_initialized_view(team, name="+edit")
+            view = create_initialized_view(team, name=self.view_name)
             self.assertTrue(view.form_fields['name'].for_display)
             self.assertEqual(
                 'This team has an active PPA with packages published and '
@@ -201,7 +202,7 @@
         removeSecurityProxy(archive).status = ArchiveStatus.DELETED
         get_property_cache(team).archive = archive
         with person_logged_in(owner):
-            view = create_initialized_view(team, name="+edit")
+            view = create_initialized_view(team, name=self.view_name)
             self.assertFalse(view.form_fields['name'].for_display)
 
     def test_cannot_rename_team_with_active_mailinglist(self):
@@ -211,7 +212,7 @@
         team = self.factory.makeTeam(owner=owner)
         self.factory.makeMailingList(team, owner)
         with person_logged_in(owner):
-            view = create_initialized_view(team, name="+edit")
+            view = create_initialized_view(team, name=self.view_name)
             self.assertTrue(view.form_fields['name'].for_display)
             self.assertEqual(
                 'This team has a mailing list and may not be renamed.',
@@ -226,7 +227,7 @@
         team_list.transitionToStatus(MailingListStatus.INACTIVE)
         team_list.purge()
         with person_logged_in(owner):
-            view = create_initialized_view(team, name="+edit")
+            view = create_initialized_view(team, name=self.view_name)
             self.assertFalse(view.form_fields['name'].for_display)
 
     def test_cannot_rename_team_with_multiple_reasons(self):
@@ -240,13 +241,19 @@
         self.factory.makeSourcePackagePublishingHistory(archive=archive)
         get_property_cache(team).archive = archive
         with person_logged_in(owner):
-            view = create_initialized_view(team, name="+edit")
+            view = create_initialized_view(team, name=self.view_name)
             self.assertTrue(view.form_fields['name'].for_display)
             self.assertEqual(
                 'This team has an active PPA with packages published and '
                 'a mailing list and may not be renamed.',
                 view.widgets['name'].hint)
 
+
+class TestTeamEditView(TestTeamPersonRenameFormMixin, TestCaseWithFactory):
+
+    layer = LaunchpadFunctionalLayer
+    view_name = '+edit'
+
     def test_edit_team_view_permission(self):
         # Only an administrator or the team owner of a team can
         # change the details of that team.
@@ -437,6 +444,29 @@
             view.errors[0].doc())
 
 
+class TeamAdminisiterViewTestCase(TestTeamPersonRenameFormMixin,
+                                  TestCaseWithFactory):
+
+    layer = LaunchpadFunctionalLayer
+    view_name = '+review'
+
+    def test_init_admin(self):
+        # An admin sees all the fields.
+        team = self.factory.makeTeam()
+        login_celebrity('admin')
+        view = create_initialized_view(team, name=self.view_name)
+        self.assertEqual('Review team', view.label)
+        self.assertEqual(
+            ['name', 'displayname'], view.field_names)
+
+    def test_init_registry_expert(self):
+        # Registry experts do no see the the displayname field.
+        team = self.factory.makeTeam()
+        login_celebrity('registry_experts')
+        view = create_initialized_view(team, name=self.view_name)
+        self.assertEqual(['name'], view.field_names)
+
+
 class TestTeamMenu(TestCaseWithFactory):
 
     layer = DatabaseFunctionalLayer