Merge ~pappacena/launchpad:oci-project-admin into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: 2cc36dab7be70fc603173563c9a5cb6d4ab846d6
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:oci-project-admin
Merge into: launchpad:master
Diff against target: 151 lines (+76/-2)
4 files modified
lib/lp/registry/interfaces/distribution.py (+9/-0)
lib/lp/registry/model/distribution.py (+15/-0)
lib/lp/registry/tests/test_distribution.py (+48/-1)
lib/lp/testing/factory.py (+4/-1)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+381321@code.launchpad.net

Commit message

Adding the attribute and method to check if a given person has permission to manage OCI projects for a given Distribution.

Description of the change

This MP only adds the new Distribution.oci_project_admin attribute and Distribution.canAdministerOCIProjects, so we can unlock the development of UI and API for OCI project creation.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

Thanks. Various comments, but nothing too major. As usual, this will need to wait until the corresponding database patch has been deployed to production and merged into master.

review: Approve
fd62276... by Thiago F. Pappacena

Removing oci_project_admin as parameter from some methods and adding special user cases

Revision history for this message
Thiago F. Pappacena (pappacena) wrote :

Thanks for the review! I'm pushing requested changes.

fdcd57d... by Thiago F. Pappacena

Merge branch 'master' into oci-project-admin

Revision history for this message
Colin Watson (cjwatson) wrote :

The corresponding database patch has landed now, so you can go ahead and land this (with one tweak).

review: Approve
2cc36da... by Thiago F. Pappacena

Removing duplicated condition on distribution.canAdministerOCIProjects

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/registry/interfaces/distribution.py b/lib/lp/registry/interfaces/distribution.py
2index 4f949e4..23bd93b 100644
3--- a/lib/lp/registry/interfaces/distribution.py
4+++ b/lib/lp/registry/interfaces/distribution.py
5@@ -274,6 +274,11 @@ class IDistributionPublic(
6 "All unofficial mirrors of this Distribution.")
7 pending_review_mirrors = Attribute(
8 "All mirrors of this Distribution that haven't been reviewed yet.")
9+ oci_project_admin = exported(PublicPersonChoice(
10+ title=_("OCI Project Administrator"),
11+ description=_("The person or team that has the rights to manage OCI "
12+ "Projects for this distribution."),
13+ required=False, vocabulary='ValidPersonOrTeam'))
14 series = exported(doNotSnapshot(
15 CollectionField(
16 title=_("DistroSeries inside this Distribution"),
17@@ -656,6 +661,10 @@ class IDistributionPublic(
18 def userCanEdit(user):
19 """Can the user edit this distribution?"""
20
21+ def canAdministerOCIProjects(person):
22+ """Checks if the given person can administer OCI Projects of this
23+ distro."""
24+
25 # XXX: pappacena 2020-04-25: This method is here on IDistributionPublic
26 # for now, until we workout the specific permission for creating OCI
27 # Projects. It's guarded by the feature flag oci.project.create.enabled.
28diff --git a/lib/lp/registry/model/distribution.py b/lib/lp/registry/model/distribution.py
29index caaad41..8d565c6 100644
30--- a/lib/lp/registry/model/distribution.py
31+++ b/lib/lp/registry/model/distribution.py
32@@ -114,6 +114,7 @@ from lp.registry.interfaces.person import (
33 )
34 from lp.registry.interfaces.pillar import IPillarNameSet
35 from lp.registry.interfaces.pocket import suffixpocket
36+from lp.registry.interfaces.role import IPersonRoles
37 from lp.registry.interfaces.series import SeriesStatus
38 from lp.registry.interfaces.sourcepackagename import ISourcePackageName
39 from lp.registry.model.announcement import MakesAnnouncements
40@@ -241,6 +242,9 @@ class Distribution(SQLBase, BugTargetBase, MakesAnnouncements,
41 mirror_admin = ForeignKey(
42 dbName='mirror_admin', foreignKey='Person',
43 storm_validator=validate_public_person, notNull=True)
44+ oci_project_admin = ForeignKey(
45+ dbName='oci_project_admin', foreignKey='Person',
46+ storm_validator=validate_public_person, notNull=False, default=None)
47 translationgroup = ForeignKey(
48 dbName='translationgroup', foreignKey='TranslationGroup',
49 notNull=False, default=None)
50@@ -1365,6 +1369,17 @@ class Distribution(SQLBase, BugTargetBase, MakesAnnouncements,
51 admins = getUtility(ILaunchpadCelebrities).admin
52 return user.inTeam(self.owner) or user.inTeam(admins)
53
54+ def canAdministerOCIProjects(self, person):
55+ """See `IDistribution`."""
56+ if person is None:
57+ return False
58+ if person.inTeam(self.oci_project_admin):
59+ return True
60+ person_roles = IPersonRoles(person)
61+ if person_roles.in_admin or person_roles.isOwner(self):
62+ return True
63+ return False
64+
65 def newSeries(self, name, display_name, title, summary,
66 description, version, previous_series, registrant):
67 """See `IDistribution`."""
68diff --git a/lib/lp/registry/tests/test_distribution.py b/lib/lp/registry/tests/test_distribution.py
69index c7bf86f..8f20b7b 100644
70--- a/lib/lp/registry/tests/test_distribution.py
71+++ b/lib/lp/registry/tests/test_distribution.py
72@@ -1,4 +1,4 @@
73-# Copyright 2009-2015 Canonical Ltd. This software is licensed under the
74+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
75 # GNU Affero General Public License version 3 (see the file LICENSE).
76
77 """Tests for Distribution."""
78@@ -689,3 +689,50 @@ class TestWebService(WebServiceTestCase):
79 self.assertEqual(
80 [],
81 ws_distro.findReferencedOOPS(start_date=now - day, end_date=now))
82+
83+
84+class DistributionOCIProjectAdminPermission(TestCaseWithFactory):
85+ layer = DatabaseFunctionalLayer
86+
87+ def test_check_oci_project_admin_person(self):
88+ person1 = self.factory.makePerson()
89+ person2 = self.factory.makePerson()
90+ distro = self.factory.makeDistribution(oci_project_admin=person1)
91+
92+ self.assertTrue(distro.canAdministerOCIProjects(person1))
93+ self.assertFalse(distro.canAdministerOCIProjects(person2))
94+ self.assertFalse(distro.canAdministerOCIProjects(None))
95+
96+ def test_check_oci_project_admin_team(self):
97+ person1 = self.factory.makePerson()
98+ person2 = self.factory.makePerson()
99+ person3 = self.factory.makePerson()
100+ team = self.factory.makeTeam(owner=person1)
101+ distro = self.factory.makeDistribution(oci_project_admin=team)
102+
103+ admin = self.factory.makeAdministrator()
104+ with person_logged_in(admin):
105+ person2.join(team)
106+
107+ self.assertTrue(distro.canAdministerOCIProjects(team))
108+ self.assertTrue(distro.canAdministerOCIProjects(person1))
109+ self.assertTrue(distro.canAdministerOCIProjects(person2))
110+ self.assertFalse(distro.canAdministerOCIProjects(person3))
111+ self.assertFalse(distro.canAdministerOCIProjects(None))
112+
113+ def test_check_oci_project_admin_without_any_admin(self):
114+ person1 = self.factory.makePerson()
115+ distro = self.factory.makeDistribution(oci_project_admin=None)
116+
117+ self.assertFalse(distro.canAdministerOCIProjects(person1))
118+ self.assertFalse(distro.canAdministerOCIProjects(None))
119+
120+ def test_check_oci_project_admin_user_and_distro_owner(self):
121+ admin = self.factory.makeAdministrator()
122+ owner = self.factory.makePerson()
123+ someone = self.factory.makePerson()
124+ distro = self.factory.makeDistribution(owner=owner)
125+
126+ self.assertFalse(distro.canAdministerOCIProjects(someone))
127+ self.assertTrue(distro.canAdministerOCIProjects(owner))
128+ self.assertTrue(distro.canAdministerOCIProjects(admin))
129diff --git a/lib/lp/testing/factory.py b/lib/lp/testing/factory.py
130index db46838..c1475af 100644
131--- a/lib/lp/testing/factory.py
132+++ b/lib/lp/testing/factory.py
133@@ -2664,7 +2664,8 @@ class BareLaunchpadObjectFactory(ObjectFactory):
134 aliases=None, bug_supervisor=None, driver=None,
135 publish_root_dir=None, publish_base_url=None,
136 publish_copy_base_url=None, no_pubconf=False,
137- icon=None, summary=None, vcs=None):
138+ icon=None, summary=None, vcs=None,
139+ oci_project_admin=None):
140 """Make a new distribution."""
141 if name is None:
142 name = self.getUniqueString(prefix="distribution")
143@@ -2692,6 +2693,8 @@ class BareLaunchpadObjectFactory(ObjectFactory):
144 naked_distro.driver = driver
145 if bug_supervisor is not None:
146 naked_distro.bug_supervisor = bug_supervisor
147+ if oci_project_admin is not None:
148+ naked_distro.oci_project_admin = oci_project_admin
149 if not no_pubconf:
150 self.makePublisherConfig(
151 distro, publish_root_dir, publish_base_url,