launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #27266
[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)