← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~sinzui/launchpad/affilliations-api into lp:launchpad

 

Curtis Hovey has proposed merging lp:~sinzui/launchpad/affilliations-api into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #185709 in Launchpad itself: "Being bug supervisor for project should associate team/user"
  https://bugs.launchpad.net/launchpad/+bug/185709

For more details, see:
https://code.launchpad.net/~sinzui/launchpad/affilliations-api/+merge/123352

Show projects that the user is a bug supervisor for.

This branch intended to rename getOwnedOrDrivenPillars() to
getAffiliatedPillars() then export it. Exporting is more complicated
than I first thought. I cut scope while I discuss the right solution.
I did see an opportunity to fix the affiliated bug supervisor bug
while reviewing my options.

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

RULES

    Pre-implementation: no one
    * Update getOwnedOrDrivePillars to search the distribution and
      product bug_supervisor column.
    * Rename getOwnedOrDrivenPillars() to getAffiliatedPillars()

    ADDENDUM
    * A view called getOwnedOrDrivenPillars() 5 times because the
      the helper property was not cached.

QA

    * Visit https://qastaging.launchpad.net/~sinzui/+related-projects
    * Verify that "Launchpad Developer Utilities" is listed on the page.


LINT

Linting changed files:
    lib/lp/registry/browser/person.py
    lib/lp/registry/doc/person-account.txt
    lib/lp/registry/doc/person.txt
    lib/lp/registry/interfaces/person.py
    lib/lp/registry/model/person.py
    lib/lp/registry/tests/test_person.py


TEST

    ./bin/test -vvc -t getAffiliatedPillars -t person-account lp.registry.tests



IMPLEMENTATION

Renamed the method. I replaced the doc test with unit tests. I updated
the method to also query for bug_supervisor.
    lib/lp/registry/doc/person-account.txt
    lib/lp/registry/doc/person.txt
    lib/lp/registry/interfaces/person.py
    lib/lp/registry/model/person.py
    lib/lp/registry/tests/test_person.py

I discovered that the method was called indirectly 5 times on some pages
because the private property was not cached.
    lib/lp/registry/browser/person.py
-- 
https://code.launchpad.net/~sinzui/launchpad/affilliations-api/+merge/123352
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~sinzui/launchpad/affilliations-api into lp:launchpad.
=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py	2012-09-06 00:01:38 +0000
+++ lib/lp/registry/browser/person.py	2012-09-07 19:46:26 +0000
@@ -675,7 +675,7 @@
     def projects(self):
         target = '+related-projects'
         text = 'Related projects'
-        enabled = bool(self.person.getOwnedOrDrivenPillars())
+        enabled = bool(self.person.getAffiliatedPillars())
         return Link(target, text, enabled=enabled, icon='info')
 
     def subscriptions(self):
@@ -3598,9 +3598,10 @@
         return self._tableHeaderMessage(
             self.related_projects_count, label='project')
 
+    @cachedproperty
     def _related_projects(self):
         """Return all projects owned or driven by this person."""
-        return self.context.getOwnedOrDrivenPillars()
+        return self.context.getAffiliatedPillars()
 
     def _tableHeaderMessage(self, count, label='package'):
         """Format a header message for the tables on the summary page."""

=== modified file 'lib/lp/registry/doc/person-account.txt'
--- lib/lp/registry/doc/person-account.txt	2012-08-07 02:31:56 +0000
+++ lib/lp/registry/doc/person-account.txt	2012-09-07 19:46:26 +0000
@@ -104,7 +104,7 @@
     True
 
     >>> foobar_pillars = []
-    >>> for pillar_name in foobar.getOwnedOrDrivenPillars():
+    >>> for pillar_name in foobar.getAffiliatedPillars():
     ...     pillar = pillar_name.pillar
     ...     if pillar.owner == foobar or pillar.driver == foobar:
     ...         foobar_pillars.append(pillar_name)
@@ -183,7 +183,7 @@
 
 ...no owned or driven pillars...
 
-    >>> foobar.getOwnedOrDrivenPillars().count()
+    >>> foobar.getAffiliatedPillars().count()
     0
 
 ...and, finally, to not be considered a valid person in Launchpad.
@@ -198,7 +198,7 @@
     >>> from lp.app.interfaces.launchpad import ILaunchpadCelebrities
     >>> registry_experts = getUtility(ILaunchpadCelebrities).registry_experts
 
-    >>> registry_pillars = set(registry_experts.getOwnedOrDrivenPillars())
+    >>> registry_pillars = set(registry_experts.getAffiliatedPillars())
     >>> registry_pillars.issuperset(foobar_pillars)
     True
 

=== modified file 'lib/lp/registry/doc/person.txt'
--- lib/lp/registry/doc/person.txt	2012-08-07 02:31:56 +0000
+++ lib/lp/registry/doc/person.txt	2012-09-07 19:46:26 +0000
@@ -1031,48 +1031,6 @@
     [u'mozilla-firefox', u'pmount']
 
 
-Pillars owned or driven by a person or team
--------------------------------------------
-
-To obtain all distributions, project groups and projects owned or driven
-by a person or team, we can use the getOwnedOrDrivenPillars() method of
-IPerson. This method returns PillarNames ordered by distribution,
-project groups and projects.
-
-    >>> login(ANONYMOUS)
-
-    >>> from lp.registry.interfaces.distribution import IDistribution
-    >>> from lp.registry.interfaces.product import IProduct
-    >>> from lp.registry.interfaces.projectgroup import IProjectGroup
-
-    >>> def print_pillar(pillarname):
-    ...     pillar = pillarname.pillar
-    ...     if IDistribution.providedBy(pillar):
-    ...         pillar_type = 'distribution'
-    ...     elif IProjectGroup.providedBy(pillar):
-    ...         pillar_type = 'project group'
-    ...     elif IProduct.providedBy(pillar):
-    ...         pillar_type = 'project'
-    ...     print "%s: %s (%s)" % (
-    ...         pillar_type, pillar.displayname, pillar.name)
-
-    >>> for pillarname in mark.getOwnedOrDrivenPillars():
-    ...     print_pillar(pillarname)
-    distribution: Debian (debian)
-    distribution: Gentoo (gentoo)
-    distribution: Kubuntu (kubuntu)
-    distribution: Red Hat (redhat)
-    project group: Apache (apache)
-    project: Derby (derby)
-    project: alsa-utils (alsa-utils)
-
-    >>> for pillarname in ubuntu_team.getOwnedOrDrivenPillars():
-    ...     print_pillar(pillarname)
-    distribution: Ubuntu (ubuntu)
-    distribution: ubuntutest (ubuntutest)
-    project: Tomcat (tomcat)
-
-
 Project owned by a person or team
 ---------------------------------
 

=== modified file 'lib/lp/registry/interfaces/person.py'
--- lib/lp/registry/interfaces/person.py	2012-08-21 04:28:11 +0000
+++ lib/lp/registry/interfaces/person.py	2012-09-07 19:46:26 +0000
@@ -1132,8 +1132,12 @@
                           the icons which represent that category.
         """
 
-    def getOwnedOrDrivenPillars():
-        """Return the pillars that this person directly owns or drives."""
+    def getAffiliatedPillars():
+        """Return the pillars that this person directly has a role with.
+
+        Returns distributions, project groups, and projects that this person
+        maintains, drives, or is the bug supervisor for.
+        """
 
     def getOwnedProjects(match_name=None):
         """Projects owned by this person or teams to which she belongs.

=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py	2012-08-30 11:48:26 +0000
+++ lib/lp/registry/model/person.py	2012-09-07 19:46:26 +0000
@@ -1117,7 +1117,7 @@
         cur.execute(query)
         return cur.fetchall()
 
-    def getOwnedOrDrivenPillars(self):
+    def getAffiliatedPillars(self):
         """See `IPerson`."""
         find_spec = (PillarName, SQL('kind'), SQL('displayname'))
         origin = SQL("""
@@ -1128,7 +1128,8 @@
                 WHERE
                     active = True AND
                     (driver = %(person)s
-                    OR owner = %(person)s)
+                    OR owner = %(person)s
+                    OR bug_supervisor = %(person)s)
                 UNION
                 SELECT name, 2 as kind, displayname
                 FROM project
@@ -1142,6 +1143,7 @@
                 WHERE
                     driver = %(person)s
                     OR owner = %(person)s
+                    OR bug_supervisor = %(person)s
                 ) _pillar
                 ON PillarName.name = _pillar.name
             """ % sqlvalues(person=self))
@@ -2223,7 +2225,7 @@
         registry_experts = getUtility(ILaunchpadCelebrities).registry_experts
         for team in Person.selectBy(teamowner=self):
             team.teamowner = registry_experts
-        for pillar_name in self.getOwnedOrDrivenPillars():
+        for pillar_name in self.getAffiliatedPillars():
             pillar = pillar_name.pillar
             # XXX flacoste 2007-11-26 bug=164635 The comparison using id below
             # works around a nasty intermittent failure.

=== modified file 'lib/lp/registry/tests/test_person.py'
--- lib/lp/registry/tests/test_person.py	2012-08-30 11:48:26 +0000
+++ lib/lp/registry/tests/test_person.py	2012-09-07 19:46:26 +0000
@@ -318,7 +318,37 @@
         self.assertEqual(None, person.homepage_content)
         self.assertEqual(None, person.teamdescription)
 
-    def test_getOwnedOrDrivenPillars(self):
+    def test_getAffiliatedPillars_kinds(self):
+        # Distributions, project groups, and projects are returned in this
+        # same order.
+        user = self.factory.makePerson()
+        project = self.factory.makeProduct(owner=user)
+        project_group = self.factory.makeProject(owner=user)
+        distribution = self.factory.makeDistribution(owner=user)
+        expected_pillars = [
+            distribution.name, project_group.name, project.name]
+        received_pillars = [
+            pillar.name for pillar in  user.getAffiliatedPillars()]
+        self.assertEqual(expected_pillars, received_pillars)
+
+    def test_getAffiliatedPillars_roles(self):
+        # owned, driven, and supervised pillars are returned ordered by
+        # display name.
+        user = self.factory.makePerson()
+        owned_project = self.factory.makeProduct(owner=user, name="cat")
+        driven_project = self.factory.makeProduct(name="bat")
+        supervised_project = self.factory.makeProduct(name='nat')
+        with celebrity_logged_in('admin'):
+            driven_project.driver = user
+            supervised_project.bug_supervisor = user
+        expected_pillars = [
+            driven_project.name, owned_project.name, supervised_project.name]
+        received_pillars = [
+            pillar.name for pillar in  user.getAffiliatedPillars()]
+        self.assertEqual(expected_pillars, received_pillars)
+
+    def test_getAffiliatedPillars_active_pillars(self):
+        # Only active pillars are returned.
         user = self.factory.makePerson()
         active_project = self.factory.makeProject(owner=user)
         inactive_project = self.factory.makeProject(owner=user)
@@ -326,7 +356,7 @@
             inactive_project.active = False
         expected_pillars = [active_project.name]
         received_pillars = [pillar.name for pillar in
-            user.getOwnedOrDrivenPillars()]
+            user.getAffiliatedPillars()]
         self.assertEqual(expected_pillars, received_pillars)
 
     def test_no_merge_pending(self):


Follow ups