← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~twom/launchpad:gdpr-overview-data into launchpad:master

 

Tom Wardill has proposed merging ~twom/launchpad:gdpr-overview-data into launchpad:master.

Commit message:
Add overview data to GDPR result

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~twom/launchpad/+git/launchpad/+merge/405641
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~twom/launchpad:gdpr-overview-data into launchpad:master.
diff --git a/lib/lp/registry/interfaces/person.py b/lib/lp/registry/interfaces/person.py
index 19b89e0..21094fa 100644
--- a/lib/lp/registry/interfaces/person.py
+++ b/lib/lp/registry/interfaces/person.py
@@ -2078,6 +2078,9 @@ class IPersonSetModerate(Interface):
     def getUserData(email):
         """Get GDPR-related data for a user from their email address."""
 
+    def getUserOverview(person):
+        """Get the overview data required for GDPR purposes."""
+
 
 class IPersonSetPublic(Interface):
     """The set of Persons."""
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index 6f46075..3d8939c 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -4088,8 +4088,49 @@ class PersonSet:
         # it does not refer to an `IAccount`.
         return_data = {"status": "account only; no other data"}
         return_data["person"] = canonical_url(account)
+        # Get the data behind the overview screen
+        overview = self.getUserOverview(account)
+        return_data.update(overview)
         return return_data
 
+    def getUserOverview(self, person):
+        """See `IPersonSet`."""
+        overview = {}
+        maintained_packages = person.hasMaintainedPackages()
+        uploaded_packages = person.hasUploadedButNotMaintainedPackages()
+        ppa_packages = person.hasUploadedPPAPackages()
+        synchronised_packages = person.hasSynchronisedPublishings()
+
+        # Related packages is a general overview, if we have any of them
+        # the related packages exist
+        if any(maintained_packages, uploaded_packages,
+               ppa_packages, synchronised_packages):
+            overview['related-packages'] = canonical_url(
+                person, view_name='+related-packages')
+
+        if maintained_packages:
+            overview['maintained-packages'] = canonical_url(
+                person, view_name="+maintained-packages")
+        if uploaded_packages:
+            overview["uploaded-packages"] = canonical_url(
+                person, view_name="+uploaded-packages")
+        if ppa_packages:
+            overview["ppa-packages"] = canonical_url(
+                person, view_name="+ppa-packages")
+        if synchronised_packages:
+            overview["synchronised-packages"] = canonical_url(
+                person, view_name="+synchronised-packages")
+
+        related_projects = not person.getAffiliatedPillars(person).is_empty()
+        if related_projects:
+            overview["related-projects"] = canonical_url(
+                person, view_name="+related-projects")
+        owned_teams = not person.getOwnedTeams(person).is_empty()
+        if owned_teams:
+            overview["owned-teams"] = canonical_url(
+                person, view_name="+owned-teams")
+        return overview
+
 
 # Provide a storm alias from Person to Owner. This is useful in queries on
 # objects that have more than just an owner associated with them.
diff --git a/lib/lp/registry/tests/test_personset.py b/lib/lp/registry/tests/test_personset.py
index 6c4427a..6cbb642 100644
--- a/lib/lp/registry/tests/test_personset.py
+++ b/lib/lp/registry/tests/test_personset.py
@@ -16,6 +16,7 @@ from zope.component import getUtility
 from zope.security.interfaces import Unauthorized
 from zope.security.proxy import removeSecurityProxy
 
+from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.code.tests.helpers import remove_all_sample_data_branches
 from lp.registry.errors import (
     InvalidName,
@@ -30,12 +31,14 @@ from lp.registry.interfaces.person import (
     PersonCreationRationale,
     TeamEmailAddressError,
     )
+from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.ssh import (
     SSHKeyAdditionError,
     SSHKeyType,
     )
 from lp.registry.model.codeofconduct import SignedCodeOfConduct
 from lp.registry.model.person import Person
+from lp.scripts.garbo import PopulateLatestPersonSourcePackageReleaseCache
 from lp.services.database.interfaces import (
     IMasterStore,
     IStore,
@@ -59,8 +62,15 @@ from lp.services.identity.interfaces.emailaddress import (
     )
 from lp.services.identity.model.account import Account
 from lp.services.identity.model.emailaddress import EmailAddress
+from lp.services.log.logger import DevNullLogger
 from lp.services.openid.model.openididentifier import OpenIdIdentifier
 from lp.services.webapp.interfaces import ILaunchBag
+from lp.services.webapp.publisher import canonical_url
+from lp.soyuz.enums import (
+    ArchivePurpose,
+    PackagePublishingStatus,
+    )
+from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
 from lp.testing import (
     admin_logged_in,
     ANONYMOUS,
@@ -72,8 +82,11 @@ from lp.testing import (
     TestCase,
     TestCaseWithFactory,
     )
-from lp.services.webapp.publisher import canonical_url
-from lp.testing.layers import DatabaseFunctionalLayer
+from lp.testing.dbuser import switch_dbuser
+from lp.testing.layers import (
+    DatabaseFunctionalLayer,
+    LaunchpadFunctionalLayer,
+    )
 from lp.testing.matchers import HasQueryCount
 
 
@@ -1137,11 +1150,39 @@ class TestPersonDeleteSSHKeyFromSSO(TestCaseWithFactory):
 
 class TestGDPRUserRetrieval(TestCaseWithFactory):
 
-    layer = DatabaseFunctionalLayer
+    layer = LaunchpadFunctionalLayer
 
     def setUp(self):
         super(TestGDPRUserRetrieval, self).setUp()
         self.person_set = getUtility(IPersonSet)
+        self.user = self.factory.makePerson()
+        self.factory.makeGPGKey(self.user)
+        self.ubuntu = getUtility(ILaunchpadCelebrities).ubuntu
+        self.warty = self.ubuntu.getSeries('warty')
+
+    def publishSources(self, archive, maintainer):
+        publisher = SoyuzTestPublisher()
+        publisher.person = self.user
+        login('foo.bar@xxxxxxxxxxxxx')
+        spphs = []
+        for count in range(0, 3):
+            source_name = "foo" + str(count)
+            spph = publisher.getPubSource(
+                sourcename=source_name,
+                status=PackagePublishingStatus.PUBLISHED,
+                archive=archive,
+                maintainer=maintainer,
+                creator=self.user,
+                distroseries=self.warty)
+            spphs.append(spph)
+        # Update the releases cache table.
+        switch_dbuser('garbo_frequently')
+        job = PopulateLatestPersonSourcePackageReleaseCache(DevNullLogger())
+        while not job.isDone():
+            job(chunk_size=100)
+        switch_dbuser('launchpad')
+        login(ANONYMOUS)
+        return spphs
 
     def test_no_data(self):
         with admin_logged_in():
@@ -1180,3 +1221,39 @@ class TestGDPRUserRetrieval(TestCaseWithFactory):
             "status": "account only; no other data",
             "person": canonical_url(person)},
             result)
+
+    def test_getUserOverview(self):
+        ppa = self.factory.makeArchive(owner=self.user)
+
+        # uploaded-packages
+        archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
+        spr = self.factory.makeSourcePackageRelease(
+            creator=self.user, archive=archive)
+        self.spph = self.factory.makeSourcePackagePublishingHistory(
+            sourcepackagerelease=spr, archive=archive)
+
+        # synchronized packages
+        dest_distroseries = self.factory.makeDistroSeries()
+        self.copied_spph = self.spph.copyTo(
+            dest_distroseries, creator=self.user,
+            pocket=PackagePublishingPocket.UPDATES,
+            archive=dest_distroseries.main_archive)
+
+        # Publish the correct amount of packages to the correct plaches
+        # Maintained packages (non-ppa)
+        self.publishSources(archive, self.user)
+        # PPA packages
+        self.publishSources(ppa, self.user)
+
+        self.factory.makeProject(owner=self.user)
+        self.factory.makeTeam(owner=self.user)
+
+        with admin_logged_in():
+            result = self.person_set.getUserOverview(self.user)
+        self.assertIn('related-packages', result)
+        self.assertIn('maintained-packages', result)
+        self.assertIn('uploaded-packages', result)
+        self.assertIn('ppa-packages', result)
+        self.assertIn('synchronised-packages', result)
+        self.assertIn('related-projects', result)
+        self.assertIn('owned-teams', result)