Merge lp:~henninge/launchpad/bug-503454-security-py into lp:launchpad

Proposed by Henning Eggers on 2010-01-12
Status: Merged
Approved by: Edwin Grubbs on 2010-01-13
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~henninge/launchpad/bug-503454-security-py
Merge into: lp:launchpad
Diff against target: 1321 lines (+302/-263)
7 files modified
lib/canonical/launchpad/doc/hasowner-authorization.txt (+5/-5)
lib/canonical/launchpad/doc/personroles.txt (+130/-0)
lib/canonical/launchpad/interfaces/launchpad.py (+8/-1)
lib/canonical/launchpad/security.py (+129/-240)
lib/canonical/launchpad/tests/test_personroles.py (+10/-4)
lib/canonical/launchpad/utilities/personroles.py (+14/-7)
lib/lp/code/doc/branch-visibility.txt (+6/-6)
To merge this branch: bzr merge lp:~henninge/launchpad/bug-503454-security-py
Reviewer Review Type Date Requested Status
Edwin Grubbs (community) code 2010-01-12 Approve on 2010-01-13
Review via email: mp+17241@code.launchpad.net

Commit message

Updated security.py to use PersonRoles. Added doctest for PersonRoles.

To post a comment you must log in.
Henning Eggers (henninge) wrote :
Download full text (3.8 KiB)

= Bug 506454 =

This is a tech-dept relief that applies some refactoring to security.py. It may seem like a lot of work for the transition but afterwards will make it more straight forward to write security checkers.

This branch introduces and API change for "checkAuthenticated" which used to receive an "IPerson" object as its "user" parameter which has now been changed to be an "IPersonRoles" object. The old object can still be reached via "user.person".

This branch also contains a change to IPersonRoles and its implementation because at least one test wanted to check the "driver" attribute of an object although the object also has a "drivers" attribute (IHasDrivers). Although this may actually be a bug (why should the driver of a product have less permissions than the driver of a productseries?) I provided an explicit isOneOfDrivers method. This also makes isDriver symmetrical to isOwner.

Some tests needed to be adapted because they used "checkAuthenticated" on an object that implements "IAuthorization". "checkAuthenticated" has been replaced by "checkAccountAuthenticated" in "IAuthorization".

The diff is overly long because of the many very similar changes in security.py.

== Implementation details ==

lib/canonical/launchpad/doc/hasowner-authorization.txt

 * Replaced checkAuthenticated with checkAccountAuthenticated.
 * Added some print statements.

lib/canonical/launchpad/doc/personroles.txt

 * New doc test for PersonRoles so people have no fear of using it in security.py. ;-)

lib/canonical/launchpad/interfaces/launchpad.py

 * Added isOneOfDrivers method to IPersonRoles interface.

lib/canonical/launchpad/security.py

 * The main change in this branch: AuthorizationBase.checkAccountAuthenticated applies the IPersonRoles adapter to the IPerson object which it derives from the account. So unless checkAccountAuthenticated gets overwritten, checkAuthenticated reveives an IPersonRoles object instead of an IPerson object.
 * Replaced all calls to user.inTeam(celebrity.some_celeb) with user.in_some_celeb.
 * Replaced owner and driver checks with the respective methods from IPersonRoles.
 * Where ever the user object is still needed as an IPerson object, it was replaced with user.person.
 * A few checkers were optimized in the course of this refactoring.

lib/canonical/launchpad/utilities/personroles.py

 * Implementation of isOneOfDrivers which is mostly the previous implementation of isDriver but now checks for the IHasDrivers interface instead of the actual attribute. (Bye-bye duck-typing, hello contract-typing. :)

lib/lp/code/doc/branch-visibility.txt

 * Mechanical replacement of checkAuthenticated with checkAccountAuthenticated.

== Tests ==

As almost all of Launchpad is affected by security.py, only the full test suite gives that feeling of security.
Test PersonRoles itself like this:

bin/test -vvct personroles -t celebrities

== QA ==

Launchpad still working as it used to? Good.

= Launchpad lint =

Checking for conflicts. and issues in doctests and templates.
Running jslint, xmllint, pyflakes, and pylint.
Using normal rules.

Linting changed files:
  lib/canonical/launchpad/security.py
  lib/canonical/launchpad/doc/hasowne...

Read more...

Henning Eggers (henninge) wrote :

Found room for a little more improvement. I'd better stop now, though. ;-)

Edwin Grubbs (edwin-grubbs) wrote :
Download full text (5.5 KiB)

Hi Henning,

This branch is a nice improvement. It's always good to shrink files.

I have a few comments below, but I also would like this change made,
which isn't actually part of your diff. In PersonRoles.__getattr__
please add info to the exception you raise so that it matches the error
python gives you for its default types such as:
    AttributeError: 'int' object has no attribute 'foo'

merge-conditional

-Edwin

>=== added file 'lib/canonical/launchpad/doc/personroles.txt'
>--- lib/canonical/launchpad/doc/personroles.txt 1970-01-01 00:00:00 +0000
>+++ lib/canonical/launchpad/doc/personroles.txt 2010-01-13 16:45:40 +0000
>@@ -0,0 +1,131 @@
>+= PersonRoles =
>+
>+To make the checking for certain roles that a person can have more convenient

This makes it a little easier to read:
    "To make it more convenient to check which roles a person has,"

>+the IPersonRoles adapter is provided. It's main use is to easily check if a
>+person is the member of a celebrity team or is a celebrity person. In
>+addition, methods for common checks are provided, too.
>+
>+The IPersonRoles interface is closely tight to the ILaunchpadCelebrities
>+interface. Any addition or removal of a person celebrity must be reflected in
>+adding or removing the corresponding property in IPersonRoles. Luckily the
>+celbrities.txt doctest includes a check for this and will give a useful
>+information of which attribute needs to be added or removed. Both interfaces

s/celbrities.txt/celebrities.txt/
s/give a useful/give useful/
s/information of/information on/

>+are found in the same file. There is no need to adapt the implementation
>+class PersonRoles, though (thanks to __getattr__).
>+
>+PersonRoles is most prominent in AuthenticationBase in security.py. The user
>+parameter to checkAuthenticated is a PersonRoles object (used to be a Person
>+object).

s/used to be/was/
or "this used to be" to differentiate it from "this is used to be".
Otherwise, it's not clear if "this" or "this is" was dropped until
you get to the middle of the sentence.

>+== The person object and the adapter ==
>+
>+PersonRoles is registered as an unnamed adapter for IPersonRoles.
>+
>+ >>> from canonical.launchpad.interfaces.launchpad import IPersonRoles
>+ >>> person = factory.makePerson()
>+ >>> print IPersonRoles(person)
>+ <canonical.launchpad.utilities.personroles.PersonRoles object at ...>
>+
>+The original Person object can be reached through the person attribute.
>+
>+ >>> roles = IPersonRoles(person)
>+ >>> print roles.person is person
>+ True
>+
>+
>+== Celebrity persons ==
>+
>+There are a number of celebrity persons defined in ILaunchpadCelebrities.
>+PersonRoles has a corresponding attribute of the same name prefixed with
>+"in_" to check if the person in question is a member of this celebrity or is
>+this celebrity. The following tests are identical.
>+
>+ >>> from canonical.launchpad.interfaces.launchpad import (
>+ ... ILaunchpadCelebrities)
>+ >>> rosetta_experts = getUtility(ILaunchpadCelebrities).rosetta_experts
>+ >>> print person.inTeam(rosetta_experts)
>+ False
>+
>+ >>> print roles.in_rosetta_experts
>+ False
>+
>+The tes...

Read more...

review: Approve (code)
Henning Eggers (henninge) wrote :

Am 13.01.2010 22:06, Edwin Grubbs schrieb:
> Review: Approve code
> Hi Henning,
>
> This branch is a nice improvement. It's always good to shrink files.
>
> I have a few comments below, but I also would like this change made,
> which isn't actually part of your diff. In PersonRoles.__getattr__
> please add info to the exception you raise so that it matches the error
> python gives you for its default types such as:
> AttributeError: 'int' object has no attribute 'foo'
>
> merge-conditional
>

Thank you very much for your suggestions which I liked very much. All
were implemented. ;-)

An incremental diff is attached.

Cheers,
Henning

1=== modified file 'lib/canonical/launchpad/doc/personroles.txt'
2--- lib/canonical/launchpad/doc/personroles.txt 2010-01-12 17:07:32 +0000
3+++ lib/canonical/launchpad/doc/personroles.txt 2010-01-14 11:19:29 +0000
4@@ -1,6 +1,6 @@
5 = PersonRoles =
6
7-To make the checking for certain roles that a person can have more convenient
8+To make it more convenient to check which roles a person has,
9 the IPersonRoles adapter is provided. It's main use is to easily check if a
10 person is the member of a celebrity team or is a celebrity person. In
11 addition, methods for common checks are provided, too.
12@@ -8,14 +8,13 @@
13 The IPersonRoles interface is closely tight to the ILaunchpadCelebrities
14 interface. Any addition or removal of a person celebrity must be reflected in
15 adding or removing the corresponding property in IPersonRoles. Luckily the
16-celbrities.txt doctest includes a check for this and will give a useful
17-information of which attribute needs to be added or removed. Both interfaces
18+celebrities.txt doctest includes a check for this and will give useful
19+information on which attribute needs to be added or removed. Both interfaces
20 are found in the same file. There is no need to adapt the implementation
21 class PersonRoles, though (thanks to __getattr__).
22
23 PersonRoles is most prominent in AuthenticationBase in security.py. The user
24-parameter to checkAuthenticated is a PersonRoles object (used to be a Person
25-object).
26+parameter to checkAuthenticated is a PersonRoles object (was a Person object).
27
28
29 == The person object and the adapter ==
30@@ -60,8 +59,8 @@
31 True
32
33 To stay consistent, all attributes are prefixed with "in_" although the
34-attributes names of ILaunchpadCelebrities are not all lexically correct
35-plurals nor are all the attributes teams. This makes for odd sounding
36+attribute names of ILaunchpadCelebrities are not all lexically correct
37+plurals, nor are all the attributes teams. This makes for odd sounding
38 attribute names in IPersonRoles.
39
40 >>> print roles.in_admin
41
42=== modified file 'lib/canonical/launchpad/security.py'
43--- lib/canonical/launchpad/security.py 2010-01-12 17:42:43 +0000
44+++ lib/canonical/launchpad/security.py 2010-01-14 11:21:36 +0000
45@@ -2215,11 +2215,10 @@
46 self.obj.person.hide_email_addresses):
47 return True
48
49- person = IPerson(account, None)
50- if person is None:
51+ user = IPersonRoles(IPerson(account, None), None)
52+ if user is None:
53 return False
54
55- user = IPersonRoles(person)
56 return (self.obj.person is not None and user.inTeam(self.obj.person)
57 or user.in_commercial_admin
58 or user.in_registry_experts
59
60=== modified file 'lib/canonical/launchpad/utilities/personroles.py'
61--- lib/canonical/launchpad/utilities/personroles.py 2010-01-12 14:52:41 +0000
62+++ lib/canonical/launchpad/utilities/personroles.py 2010-01-14 11:10:40 +0000
63@@ -26,10 +26,14 @@
64 def __getattr__(self, name):
65 """Handle all in_* attributes."""
66 prefix = 'in_'
67+ errortext = "'PersonRoles' object has no attribute '%s'" % name
68 if not name.startswith(prefix):
69- raise AttributeError
70+ raise AttributeError(errortext)
71 attribute = name[len(prefix):]
72- return self.person.inTeam(getattr(self._celebrities, attribute))
73+ try:
74+ return self.person.inTeam(getattr(self._celebrities, attribute))
75+ except AttributeError:
76+ raise AttributeError(errortext)
77
78 def isOwner(self, obj):
79 """See IPersonRoles."""

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/doc/hasowner-authorization.txt'
2--- lib/canonical/launchpad/doc/hasowner-authorization.txt 2009-08-13 15:12:16 +0000
3+++ lib/canonical/launchpad/doc/hasowner-authorization.txt 2010-01-15 07:14:13 +0000
4@@ -18,23 +18,23 @@
5 >>> from canonical.launchpad.webapp.interfaces import IAuthorization
6 >>> from zope.component import queryAdapter
7 >>> authorization = queryAdapter(foo, IAuthorization, 'launchpad.Edit')
8- >>> authorization.checkAuthenticated(salgado)
9+ >>> print authorization.checkAccountAuthenticated(salgado.account)
10 True
11
12 So can a member of the Launchpad admins team.
13
14 >>> mark = getUtility(IPersonSet).getByName('mark')
15 >>> admins = getUtility(IPersonSet).getByName('admins')
16- >>> mark.inTeam(admins)
17+ >>> print mark.inTeam(admins)
18 True
19- >>> authorization.checkAuthenticated(mark)
20+ >>> print authorization.checkAccountAuthenticated(mark.account)
21 True
22
23 But someone who's not salgado nor a member of the admins team won't be
24 able to.
25
26 >>> sample_person = getUtility(IPersonSet).getByName('name12')
27- >>> sample_person.inTeam(admins)
28+ >>> print sample_person.inTeam(admins)
29 False
30- >>> authorization.checkAuthenticated(sample_person)
31+ >>> print authorization.checkAccountAuthenticated(sample_person)
32 False
33
34=== added file 'lib/canonical/launchpad/doc/personroles.txt'
35--- lib/canonical/launchpad/doc/personroles.txt 1970-01-01 00:00:00 +0000
36+++ lib/canonical/launchpad/doc/personroles.txt 2010-01-15 07:14:13 +0000
37@@ -0,0 +1,130 @@
38+= PersonRoles =
39+
40+To make it more convenient to check which roles a person has,
41+the IPersonRoles adapter is provided. It's main use is to easily check if a
42+person is the member of a celebrity team or is a celebrity person. In
43+addition, methods for common checks are provided, too.
44+
45+The IPersonRoles interface is closely tight to the ILaunchpadCelebrities
46+interface. Any addition or removal of a person celebrity must be reflected in
47+adding or removing the corresponding property in IPersonRoles. Luckily the
48+celebrities.txt doctest includes a check for this and will give useful
49+information on which attribute needs to be added or removed. Both interfaces
50+are found in the same file. There is no need to adapt the implementation
51+class PersonRoles, though (thanks to __getattr__).
52+
53+PersonRoles is most prominent in AuthenticationBase in security.py. The user
54+parameter to checkAuthenticated is a PersonRoles object (was a Person object).
55+
56+
57+== The person object and the adapter ==
58+
59+PersonRoles is registered as an unnamed adapter for IPersonRoles.
60+
61+ >>> from canonical.launchpad.interfaces.launchpad import IPersonRoles
62+ >>> person = factory.makePerson()
63+ >>> print IPersonRoles(person)
64+ <canonical.launchpad.utilities.personroles.PersonRoles object at ...>
65+
66+The original Person object can be reached through the person attribute.
67+
68+ >>> roles = IPersonRoles(person)
69+ >>> print roles.person is person
70+ True
71+
72+
73+== Celebrity persons ==
74+
75+There are a number of celebrity persons defined in ILaunchpadCelebrities.
76+PersonRoles has a corresponding attribute of the same name prefixed with
77+"in_" to check if the person in question is a member of this celebrity or is
78+this celebrity. The following tests are identical.
79+
80+ >>> from canonical.launchpad.interfaces.launchpad import (
81+ ... ILaunchpadCelebrities)
82+ >>> rosetta_experts = getUtility(ILaunchpadCelebrities).rosetta_experts
83+ >>> print person.inTeam(rosetta_experts)
84+ False
85+
86+ >>> print roles.in_rosetta_experts
87+ False
88+
89+The test will succeed once we make person a member of the team. Need to be an
90+admin to do that.
91+
92+ >>> login("foo.bar@canonical.com")
93+ >>> rosetta_experts.addMember(person, rosetta_experts.teamowner)
94+ (True, ...Approved>)
95+ >>> print roles.in_rosetta_experts
96+ True
97+
98+To stay consistent, all attributes are prefixed with "in_" although the
99+attribute names of ILaunchpadCelebrities are not all lexically correct
100+plurals, nor are all the attributes teams. This makes for odd sounding
101+attribute names in IPersonRoles.
102+
103+ >>> print roles.in_admin
104+ False
105+ >>> print roles.in_janitor
106+ False
107+
108+ >>> janitor = getUtility(ILaunchpadCelebrities).janitor
109+ >>> janitor_roles = IPersonRoles(janitor)
110+ >>> print janitor_roles.in_janitor
111+ True
112+
113+
114+== inTeam ==
115+
116+The Person.inTeam method is available directly through PersonRoles. This can
117+be used to check for any non-celebrity team.
118+
119+ >>> new_team = factory.makeTeam()
120+ >>> new_team.addMember(person, new_team.teamowner)
121+ (True, ...Approved>)
122+ >>> print person.inTeam(new_team)
123+ True
124+
125+ >>> print roles.inTeam(new_team)
126+ True
127+
128+
129+== isOwner, isDriver ==
130+
131+We can easily check for ownership and drivership. This is admittedly not much
132+shorter than calling inTeam but clearer to read.
133+
134+ >>> product = factory.makeProduct(owner=person)
135+ >>> print roles.isOwner(product)
136+ True
137+
138+ >>> print roles.isDriver(product)
139+ False
140+ >>> product.driver = person
141+ >>> print roles.isDriver(product)
142+ True
143+
144+
145+== isOneOfDrivers ==
146+
147+If an object implements IHasDrivers it lists all drivers of the object and
148+possible parent objects. The method isOneOfDrivers lets us check for those.
149+
150+ >>> productseries = factory.makeProductSeries(product=product)
151+ >>> print roles.isDriver(productseries)
152+ False
153+ >>> print roles.isOneOfDrivers(productseries)
154+ True
155+
156+
157+== isOneOf ==
158+
159+Finally, sometimes a person may be one of multiple roles for an object. The
160+method isOneOf makes checking all of these a breeze.
161+
162+ >>> spec = factory.makeSpecification()
163+ >>> spec.assignee = person
164+ >>> print roles.isOwner(spec)
165+ False
166+ >>> print roles.isOneOf(spec, ['owner', 'approver', 'assignee'])
167+ True
168
169=== modified file 'lib/canonical/launchpad/interfaces/launchpad.py'
170--- lib/canonical/launchpad/interfaces/launchpad.py 2010-01-12 15:39:36 +0000
171+++ lib/canonical/launchpad/interfaces/launchpad.py 2010-01-15 07:14:13 +0000
172@@ -223,7 +223,14 @@
173 """Is this person the owner of the object?"""
174
175 def isDriver(obj):
176- """Is this person one of the drivers of the object?"""
177+ """Is this person the driver of the object?"""
178+
179+ def isOneOfDrivers(obj):
180+ """Is this person on of the drivers of the object?
181+
182+ Works on objects that implement 'IHasDrivers' but will default to
183+ isDriver if it doesn't, i.e. check the driver attribute.
184+ """
185
186 def isOneOf(obj, attributes):
187 """Is this person one of the roles in relation to the object?
188
189=== modified file 'lib/canonical/launchpad/security.py'
190--- lib/canonical/launchpad/security.py 2010-01-13 06:50:43 +0000
191+++ lib/canonical/launchpad/security.py 2010-01-15 07:14:13 +0000
192@@ -154,7 +154,7 @@
193 if person is None:
194 return self.checkUnauthenticated()
195 else:
196- return self.checkAuthenticated(person)
197+ return self.checkAuthenticated(IPersonRoles(person))
198
199
200 class ViewByLoggedInUser(AuthorizationBase):
201@@ -176,8 +176,7 @@
202 usedfor = Interface
203
204 def checkAuthenticated(self, user):
205- admins = getUtility(ILaunchpadCelebrities).admin
206- return user.inTeam(admins)
207+ return user.in_admin
208
209
210 class AdminByCommercialTeamOrAdmins(AuthorizationBase):
211@@ -185,9 +184,7 @@
212 usedfor = Interface
213
214 def checkAuthenticated(self, user):
215- celebrities = getUtility(ILaunchpadCelebrities)
216- return (user.inTeam(celebrities.commercial_admin)
217- or user.inTeam(celebrities.admin))
218+ return user.in_commercial_admin or user.in_admin
219
220
221 class EditByRegistryExpertsOrAdmins(AuthorizationBase):
222@@ -195,7 +192,6 @@
223 usedfor = ILaunchpadRoot
224
225 def checkAuthenticated(self, user):
226- user = IPersonRoles(user)
227 return user.in_admin or user.in_registry_experts
228
229
230@@ -204,7 +200,6 @@
231 usedfor = None
232
233 def checkAuthenticated(self, user):
234- user = IPersonRoles(user)
235 return user.in_admin or user.in_registry_experts
236
237
238@@ -241,7 +236,6 @@
239 if self.obj.active:
240 return True
241 else:
242- user = IPersonRoles(user)
243 return (user.in_commercial_admin or
244 user.in_admin or
245 user.in_registry_experts)
246@@ -258,7 +252,6 @@
247 EditAccountBySelfOrAdmin, self).checkAccountAuthenticated(account)
248
249 def checkAuthenticated(self, user):
250- user = IPersonRoles(user)
251 return user.in_admin
252
253
254@@ -271,7 +264,6 @@
255
256 def checkAuthenticated(self, user):
257 """Extend permission to registry experts."""
258- user = IPersonRoles(user)
259 return user.in_admin or user.in_registry_experts
260
261
262@@ -280,7 +272,6 @@
263 permission = 'launchpad.Moderate'
264
265 def checkAuthenticated(self, user):
266- user = IPersonRoles(user)
267 return user.in_admin or user.in_registry_experts
268
269
270@@ -289,8 +280,7 @@
271 usedfor = IOAuthAccessToken
272
273 def checkAuthenticated(self, user):
274- return (self.obj.person == user
275- or user.inTeam(getUtility(ILaunchpadCelebrities).admin))
276+ return self.obj.person == user or user.in_admin
277
278
279 class EditOAuthRequestToken(EditOAuthAccessToken):
280@@ -303,7 +293,7 @@
281 usedfor = IBugNomination
282
283 def checkAuthenticated(self, user):
284- return self.obj.canApprove(user)
285+ return self.obj.canApprove(user.person)
286
287
288 class EditByOwnersOrAdmins(AuthorizationBase):
289@@ -311,8 +301,7 @@
290 usedfor = IHasOwner
291
292 def checkAuthenticated(self, user):
293- return (user.inTeam(self.obj.owner)
294- or user.inTeam(getUtility(ILaunchpadCelebrities).admin))
295+ return user.isOwner(self.obj) or user.in_admin
296
297
298 class EditProduct(EditByOwnersOrAdmins):
299@@ -338,9 +327,8 @@
300 usedfor = IDistributionMirror
301
302 def checkAuthenticated(self, user):
303- admins = getUtility(ILaunchpadCelebrities).admin
304- return (user.inTeam(self.obj.distribution.owner) or
305- user.inTeam(admins) or
306+ return (user.isOwner(self.obj.distribution) or
307+ user.in_admin or
308 user.inTeam(self.obj.distribution.mirror_admin))
309
310
311@@ -350,9 +338,8 @@
312 usedfor = IDistributionMirror
313
314 def checkAuthenticated(self, user):
315- admins = getUtility(ILaunchpadCelebrities).admin
316- return (user.inTeam(self.obj.owner) or user.inTeam(admins) or
317- user.inTeam(self.obj.distribution.owner) or
318+ return (user.isOwner(self.obj) or user.in_admin or
319+ user.isOwner(self.obj.distribution) or
320 user.inTeam(self.obj.distribution.mirror_admin))
321
322
323@@ -392,22 +379,14 @@
324
325 def checkAuthenticated(self, user):
326 assert self.obj.target
327- admins = getUtility(ILaunchpadCelebrities).admin
328- goaldrivers = []
329- goalowner = None
330- if self.obj.goal is not None:
331- goalowner = self.obj.goal.owner
332- goaldrivers = self.obj.goal.drivers
333- for driver in goaldrivers:
334- if user.inTeam(driver):
335+ goal = self.obj.goal
336+ if goal is not None:
337+ if user.isOwner(goal) or user.isOneOfDrivers(goal):
338 return True
339- return (user.inTeam(self.obj.target.owner) or
340- user.inTeam(goalowner) or
341- user.inTeam(self.obj.owner) or
342- user.inTeam(self.obj.drafter) or
343- user.inTeam(self.obj.assignee) or
344- user.inTeam(self.obj.approver) or
345- user.inTeam(admins))
346+ return (user.in_admin or
347+ user.isOwner(self.obj.target) or
348+ user.isOneOf(
349+ self.obj, ['owner','drafter', 'assignee', 'approver']))
350
351
352 class AdminSpecification(AuthorizationBase):
353@@ -416,13 +395,9 @@
354
355 def checkAuthenticated(self, user):
356 assert self.obj.target
357- targetowner = self.obj.target.owner
358- targetdrivers = self.obj.target.drivers
359- for driver in targetdrivers:
360- if user.inTeam(driver):
361- return True
362- admins = getUtility(ILaunchpadCelebrities).admin
363- return (user.inTeam(targetowner) or user.inTeam(admins))
364+ return (user.isOwner(self.obj.target) or
365+ user.isOneOfDrivers(self.obj.target) or
366+ user.in_admin)
367
368
369 class DriverSpecification(AuthorizationBase):
370@@ -448,10 +423,8 @@
371 usedfor = ISprintSpecification
372
373 def checkAuthenticated(self, user):
374- admins = getUtility(ILaunchpadCelebrities).admin
375- return (user.inTeam(self.obj.sprint.owner) or
376- user.inTeam(self.obj.sprint.driver) or
377- user.inTeam(admins))
378+ sprint = self.obj.sprint
379+ return user.isOwner(sprint) or user.isDriver(sprint) or user.in_admin
380
381
382 class DriveSprint(AuthorizationBase):
383@@ -462,10 +435,9 @@
384 usedfor = ISprint
385
386 def checkAuthenticated(self, user):
387- admins = getUtility(ILaunchpadCelebrities).admin
388- return (user.inTeam(self.obj.owner) or
389- user.inTeam(self.obj.driver) or
390- user.inTeam(admins))
391+ return (user.isOwner(self.obj) or
392+ user.isDriver(self.obj) or
393+ user.in_admin)
394
395
396 class Sprint(AuthorizationBase):
397@@ -474,12 +446,11 @@
398 usedfor = ISprint
399
400 def checkAuthenticated(self, user):
401- admins = getUtility(ILaunchpadCelebrities).admin
402- return (user.inTeam(self.obj.owner) or
403- user.inTeam(self.obj.driver) or
404- user in [attendance.attendee
405- for attendance in self.obj.attendances] or
406- user.inTeam(admins))
407+ return (user.isOwner(self.obj) or
408+ user.isDriver(self.obj) or
409+ user.person in [attendance.attendee
410+ for attendance in self.obj.attendances] or
411+ user.in_admin)
412
413
414 class EditSpecificationSubscription(AuthorizationBase):
415@@ -489,21 +460,17 @@
416 usedfor = ISpecificationSubscription
417
418 def checkAuthenticated(self, user):
419- admins = getUtility(ILaunchpadCelebrities).admin
420 if self.obj.specification.goal is not None:
421- for driver in self.obj.specification.goal.drivers:
422- if user.inTeam(driver):
423- return True
424+ if user.isOneOfDrivers(self.obj.specification.goal):
425+ return True
426 else:
427- for driver in self.obj.specification.target.drivers:
428- if user.inTeam(driver):
429- return True
430+ if user.isOneOfDrivers(self.obj.specification.target):
431+ return True
432 return (user.inTeam(self.obj.person) or
433- user.inTeam(self.obj.specification.owner) or
434- user.inTeam(self.obj.specification.assignee) or
435- user.inTeam(self.obj.specification.drafter) or
436- user.inTeam(self.obj.specification.approver) or
437- user.inTeam(admins))
438+ user.isOneOf(
439+ self.obj.specification,
440+ ['owner','drafter', 'assignee', 'approver']) or
441+ user.in_admin)
442
443
444 class OnlyRosettaExpertsAndAdmins(AuthorizationBase):
445@@ -512,7 +479,6 @@
446
447 def checkAuthenticated(self, user):
448 """Allow Launchpad's admins and Rosetta experts edit all fields."""
449- user = IPersonRoles(user)
450 return user.in_admin or user.in_rosetta_experts
451
452
453@@ -526,7 +492,6 @@
454 Any Launchpad/Launchpad Translations administrator or owners are
455 able to change translation settings for a product.
456 """
457- user = IPersonRoles(user)
458 return (user.isOwner(self.obj) or
459 user.in_rosetta_experts or
460 user.in_admin)
461@@ -537,8 +502,7 @@
462 usedfor = IProductSeries
463
464 def checkAuthenticated(self, user):
465- vcs_imports = getUtility(ILaunchpadCelebrities).vcs_imports
466- return user.inTeam(vcs_imports)
467+ return user.in_vcs_imports
468
469
470 class EditProjectMilestoneNever(AuthorizationBase):
471@@ -556,16 +520,15 @@
472
473 def checkAuthenticated(self, user):
474 """Authorize the product or distribution owner."""
475- celebrities = getUtility(ILaunchpadCelebrities)
476- if user.inTeam(celebrities.admin):
477+ if user.in_admin:
478 return True
479 if (self.obj.series_target is not None
480- and user.inTeam(self.obj.series_target.driver)):
481+ and user.isDriver(self.obj.series_target)):
482 # The user is a release manager.
483 # XXX sinzui 2009-07-18 bug=40978: The series_target should never
484 # be None, but Milestones in the production DB are like this.
485 return True
486- return user.inTeam(self.obj.target.owner)
487+ return user.isOwner(self.obj.target)
488
489 class AdminMilestoneByLaunchpadAdmins(AuthorizationBase):
490 permission = 'launchpad.Admin'
491@@ -575,8 +538,7 @@
492 """Only the Launchpad admins need this, we are only going to use it
493 for connecting up series and distroseriess where we did not have
494 them."""
495- admins = getUtility(ILaunchpadCelebrities).admin
496- return user.inTeam(admins)
497+ return user.in_admin
498
499
500 class ModeratePersonSetByExpertsOrAdmins(ReviewByRegistryExpertsOrAdmins):
501@@ -591,8 +553,7 @@
502 def checkAuthenticated(self, user):
503 """Only the team owner and Launchpad admins need this.
504 """
505- admins = getUtility(ILaunchpadCelebrities).admin
506- return user.inTeam(self.obj.teamowner) or user.inTeam(admins)
507+ return user.inTeam(self.obj.teamowner) or user.in_admin
508
509
510 class EditTeamByTeamOwnerOrTeamAdminsOrAdmins(AuthorizationBase):
511@@ -650,8 +611,7 @@
512 """
513 if self.obj.team.visibility == PersonVisibility.PUBLIC:
514 return True
515- admins = getUtility(ILaunchpadCelebrities).admin
516- if user.inTeam(admins) or user.inTeam(self.obj.team):
517+ if user.in_admin or user.inTeam(self.obj.team):
518 return True
519 return False
520
521@@ -665,8 +625,7 @@
522
523 The admin team can also edit any Person.
524 """
525- admins = getUtility(ILaunchpadCelebrities).admin
526- return self.obj.id == user.id or user.inTeam(admins)
527+ return self.obj.id == user.person.id or user.in_admin
528
529
530 class EditTranslationsPersonByPerson(AuthorizationBase):
531@@ -675,8 +634,7 @@
532
533 def checkAuthenticated(self, user):
534 person = self.obj.person
535- admins = getUtility(ILaunchpadCelebrities).admin
536- return person == user or user.inTeam(admins)
537+ return person == user.person or user.in_admin
538
539
540 class ViewPersonLocation(AuthorizationBase):
541@@ -690,8 +648,7 @@
542 if self.obj.visible:
543 return True
544 else:
545- admins = getUtility(ILaunchpadCelebrities).admin
546- return user == self.obj.person or user.inTeam(admins)
547+ return user.person == self.obj.person or user.in_admin
548
549
550 class EditPersonBySelf(AuthorizationBase):
551@@ -700,7 +657,7 @@
552
553 def checkAuthenticated(self, user):
554 """A user can edit the Person who is herself."""
555- return self.obj.id == user.id
556+ return self.obj.id == user.person.id
557
558
559 class ViewPublicOrPrivateTeamMembers(AuthorizationBase):
560@@ -718,26 +675,21 @@
561 return True
562 return False
563
564- def checkAccountAuthenticated(self, account):
565- """See `IAuthorization.checkAccountAuthenticated`.
566-
567- Verify that the user can view the team's membership.
568+ def checkAuthenticated(self, user):
569+ """Verify that the user can view the team's membership.
570
571 Anyone can see a public team's membership. Only a team member
572 or a Launchpad admin can view a private membership.
573 """
574 if self.obj.visibility == PersonVisibility.PUBLIC:
575 return True
576- user = IPerson(account, None)
577- if user is None:
578- return False
579- admins = getUtility(ILaunchpadCelebrities).admin
580- if user.inTeam(admins) or user.inTeam(self.obj):
581+ if user.in_admin or user.inTeam(self.obj):
582 return True
583 # We also grant visibility of the private team to administrators of
584 # other teams that have been invited to join the private team.
585 for invitee in self.obj.invited_members:
586- if invitee.is_team and invitee in user.getAdministratedTeams():
587+ if (invitee.is_team and
588+ invitee in user.person.getAdministratedTeams()):
589 return True
590 return False
591
592@@ -779,9 +731,7 @@
593 usedfor = IDistribution
594
595 def checkAuthenticated(self, user):
596- admins = getUtility(ILaunchpadCelebrities).admin
597- return (user.inTeam(self.obj.owner) or
598- user.inTeam(admins))
599+ return user.isOwner(self.obj) or user.in_admin
600
601
602 class AppendDistributionByDriversOrOwnersOrAdmins(AuthorizationBase):
603@@ -794,13 +744,11 @@
604 usedfor = IDistribution
605
606 def checkAuthenticated(self, user):
607- if user.inTeam(self.obj.driver) and not self.obj.full_functionality:
608+ if user.isDriver(self.obj) and not self.obj.full_functionality:
609 # Drivers of derivative distributions can create a series that
610 # they will be the release manager for.
611 return True
612- admins = getUtility(ILaunchpadCelebrities).admin
613- return (user.inTeam(self.obj.owner) or
614- user.inTeam(admins))
615+ return user.isOwner(self.obj) or user.in_admin
616
617
618 class EditDistributionSourcePackageByDistroOwnersOrAdmins(AuthorizationBase):
619@@ -810,9 +758,8 @@
620 usedfor = IDistributionSourcePackage
621
622 def checkAuthenticated(self, user):
623- admins = getUtility(ILaunchpadCelebrities).admin
624 return (user.inTeam(self.obj.distribution.owner) or
625- user.inTeam(admins))
626+ user.in_admin)
627
628
629 class AdminDistroSeries(AdminByAdminsTeam):
630@@ -846,10 +793,9 @@
631 # The series driver (release manager) may edit a series if the
632 # distribution is an `IDerivativeDistribution`
633 return True
634- admins = getUtility(ILaunchpadCelebrities).admin
635 return (user.inTeam(self.obj.owner) or
636 user.inTeam(self.obj.distribution.owner) or
637- user.inTeam(admins))
638+ user.in_admin)
639
640
641 class SeriesDrivers(AuthorizationBase):
642@@ -862,11 +808,9 @@
643 usedfor = IHasDrivers
644
645 def checkAuthenticated(self, user):
646- for driver in self.obj.drivers:
647- if user.inTeam(driver):
648- return True
649- admins = getUtility(ILaunchpadCelebrities).admin
650- return user.inTeam(self.obj.owner) or user.inTeam(admins)
651+ return (user.isOneOfDrivers(self.obj) or
652+ user.isOwner(self.obj) or
653+ user.in_admin)
654
655
656 class ViewProductSeries(AuthorizationBase):
657@@ -901,10 +845,9 @@
658 # Rosetta experts need to be able to upload translations.
659 # Bazaar experts need to be able to change the linked branches.
660 # Registry admins are just special.
661- celebrities = getUtility(ILaunchpadCelebrities)
662- if (user.inTeam(celebrities.registry_experts) or
663- user.inTeam(celebrities.bazaar_experts) or
664- user.inTeam(celebrities.rosetta_experts)):
665+ if (user.in_registry_experts or
666+ user.in_bazaar_experts or
667+ user.in_rosetta_experts):
668 return True
669 return EditByOwnersOrAdmins.checkAuthenticated(self, user)
670
671@@ -920,9 +863,8 @@
672 usedfor = IHasBug
673
674 def checkAuthenticated(self, user):
675- admins = getUtility(ILaunchpadCelebrities).admin
676
677- if user.inTeam(admins):
678+ if user.in_admin:
679 # Admins can always edit bugtasks, whether they're reported on a
680 # private bug or not.
681 return True
682@@ -946,7 +888,7 @@
683 usedfor = IHasBug
684
685 def checkAuthenticated(self, user):
686- return self.obj.bug.userCanView(user)
687+ return self.obj.bug.userCanView(user.person)
688
689 def checkUnauthenticated(self):
690 """Allow anonymous users to see non-private bugs only."""
691@@ -962,11 +904,10 @@
692 """Allow any logged in user to edit a public bug, and only
693 explicit subscribers to edit private bugs.
694 """
695- admins = getUtility(ILaunchpadCelebrities).admin
696 if not self.obj.private:
697 # This is a public bug.
698 return True
699- elif user.inTeam(admins):
700+ elif user.in_admin:
701 # Admins can edit all bugs.
702 return True
703 else:
704@@ -990,7 +931,7 @@
705 """Allow any user to see non-private bugs, but only explicit
706 subscribers to see private bugs.
707 """
708- return self.obj.userCanView(user)
709+ return self.obj.userCanView(user.person)
710
711 def checkUnauthenticated(self):
712 """Allow anonymous users to see non-private bugs only."""
713@@ -1056,17 +997,11 @@
714 return True
715
716 # Project drivers can view any project announcements.
717- assert self.obj.target
718- if self.obj.target.drivers:
719- for driver in self.obj.target.drivers:
720- if user.inTeam(driver):
721- return True
722- if user.inTeam(self.obj.target.owner):
723- return True
724-
725 # Launchpad admins can view any announcement.
726- admins = getUtility(ILaunchpadCelebrities).admin
727- return user.inTeam(admins)
728+ assert self.obj.target
729+ return (user.isOneOfDrivers(self.obj.target) or
730+ user.isOwner(self.obj.target) or
731+ user.in_admin)
732
733
734 class EditAnnouncement(AuthorizationBase):
735@@ -1077,15 +1012,9 @@
736 """Allow the project owner and drivers to edit any project news."""
737
738 assert self.obj.target
739- if self.obj.target.drivers:
740- for driver in self.obj.target.drivers:
741- if user.inTeam(driver):
742- return True
743- if user.inTeam(self.obj.target.owner):
744- return True
745-
746- admins = getUtility(ILaunchpadCelebrities).admin
747- return user.inTeam(admins)
748+ return (user.isOneOfDrivers(self.obj.target) or
749+ user.isOwner(self.obj.target) or
750+ user.in_admin)
751
752
753 class UseApiDoc(AuthorizationBase):
754@@ -1101,9 +1030,7 @@
755 experts."""
756
757 def checkAuthenticated(self, user):
758- bzrexperts = getUtility(ILaunchpadCelebrities).bazaar_experts
759- admins = getUtility(ILaunchpadCelebrities).admin
760- return user.inTeam(admins) or user.inTeam(bzrexperts)
761+ return user.in_admin or user.in_bazaar_experts
762
763
764 class OnlyVcsImportsAndAdmins(AuthorizationBase):
765@@ -1111,9 +1038,7 @@
766 experts."""
767
768 def checkAuthenticated(self, user):
769- vcsexpert = getUtility(ILaunchpadCelebrities).vcs_imports
770- admins = getUtility(ILaunchpadCelebrities).admin
771- return user.inTeam(admins) or user.inTeam(vcsexpert)
772+ return user.in_admin or user.in_vcs_imports
773
774
775 class AdminTheBazaar(OnlyVcsImportsAndAdmins):
776@@ -1252,11 +1177,10 @@
777 def checkAuthenticated(self, user):
778 """Allow anyone that can edit translations, owner, experts and admis.
779 """
780- rosetta_experts = getUtility(ILaunchpadCelebrities).rosetta_experts
781
782 return (EditByOwnersOrAdmins.checkAuthenticated(self, user) or
783- self.obj.canEditTranslations(user) or
784- user.inTeam(rosetta_experts))
785+ self.obj.canEditTranslations(user.person) or
786+ user.in_rosetta_experts)
787
788
789 class AdminTranslator(OnlyRosettaExpertsAndAdmins):
790@@ -1370,7 +1294,7 @@
791
792 # As a special case, the Ubuntu translation group owners can
793 # manage Ubuntu uploads.
794- if self.obj.isUbuntuAndIsUserTranslationGroupOwner(user):
795+ if self.obj.isUbuntuAndIsUserTranslationGroupOwner(user.person):
796 return True
797
798 return False
799@@ -1386,7 +1310,7 @@
800 """
801 if AdminTranslationImportQueueEntry.checkAuthenticated(self, user):
802 return True
803- if self.obj.isUserUploaderOrOwner(user):
804+ if self.obj.isUserUploaderOrOwner(user.person):
805 return True
806
807 return False
808@@ -1408,7 +1332,7 @@
809
810 permission_set = getUtility(IArchivePermissionSet)
811 permissions = permission_set.componentsForQueueAdmin(
812- self.obj.distroseries.main_archive, user)
813+ self.obj.distroseries.main_archive, user.person)
814 return permissions.count() > 0
815
816
817@@ -1431,7 +1355,7 @@
818
819 permission_set = getUtility(IArchivePermissionSet)
820 permissions = permission_set.componentsForQueueAdmin(
821- self.obj.archive, user)
822+ self.obj.archive, user.person)
823 if permissions.count() == 0:
824 return False
825 allowed_components = set(
826@@ -1449,11 +1373,7 @@
827
828 def checkAuthenticated(self, user):
829 """Allow admins and buildd_admins."""
830- lp_admin = getUtility(ILaunchpadCelebrities).admin
831- if user.inTeam(lp_admin):
832- return True
833- buildd_admin = getUtility(ILaunchpadCelebrities).buildd_admin
834- return user.inTeam(buildd_admin)
835+ return user.in_buildd_admin or user.in_admin
836
837
838 class AdminBuilderSet(AdminByBuilddAdmin):
839@@ -1500,11 +1420,12 @@
840 # Primary or partner section here: is the user in question allowed
841 # to upload to the respective component? Allow user to retry build
842 # if so.
843- if self.obj.archive.canUpload(user, self.obj.current_component):
844+ archive = self.obj.archive
845+ if archive.canUpload(user.person, self.obj.current_component):
846 return True
847 else:
848- return self.obj.archive.canUpload(
849- user, self.obj.sourcepackagerelease.sourcepackagename)
850+ return archive.canUpload(
851+ user.person, self.obj.sourcepackagerelease.sourcepackagename)
852
853
854 class ViewBuildRecord(EditBuildRecord):
855@@ -1524,8 +1445,7 @@
856 return True
857
858 # LP admins may also see it.
859- lp_admin = getUtility(ILaunchpadCelebrities).admin
860- if user.inTeam(lp_admin):
861+ if user.in_admin:
862 return True
863
864 # If the permission check on the sourcepackagerelease for this
865@@ -1611,10 +1531,10 @@
866
867 def can_edit_team(team, user):
868 """Return True if the given user has edit rights for the given team."""
869- if user.inTeam(getUtility(ILaunchpadCelebrities).admin):
870+ if user.in_admin:
871 return True
872 else:
873- return team in user.getAdministratedTeams()
874+ return team in user.person.getAdministratedTeams()
875
876
877 class AdminLanguageSet(OnlyRosettaExpertsAndAdmins):
878@@ -1638,7 +1558,7 @@
879 usedfor = IBranch
880
881 def checkAuthenticated(self, user):
882- return self.obj.visibleByUser(user)
883+ return self.obj.visibleByUser(user.person)
884
885 def checkUnauthenticated(self):
886 return self.obj.visibleByUser(None)
887@@ -1652,7 +1572,7 @@
888 def checkAuthenticated(self, user):
889 can_edit = (
890 user.inTeam(self.obj.owner) or
891- user_has_special_branch_access(user) or
892+ user_has_special_branch_access(user.person) or
893 can_upload_linked_package(user, self.obj))
894 if can_edit:
895 return True
896@@ -1666,12 +1586,12 @@
897 return False
898 vcs_imports = getUtility(ILaunchpadCelebrities).vcs_imports
899 return (
900- user.inTeam(vcs_imports)
901+ user.in_vcs_imports
902 or (self.obj.owner == vcs_imports
903 and user.inTeam(code_import.registrant)))
904
905
906-def can_upload_linked_package(person, branch):
907+def can_upload_linked_package(person_role, branch):
908 """True if person may upload the package linked to `branch`."""
909 # No associated `ISuiteSourcePackage` data -> not an official branch.
910 # Abort.
911@@ -1686,7 +1606,7 @@
912 # one combination that allows us to upload the corresponding source
913 # package.
914 for ssp in ssp_list:
915- if can_upload_to_archive(person, ssp):
916+ if can_upload_to_archive(person_role.person, ssp):
917 return True
918 return False
919
920@@ -1697,9 +1617,8 @@
921 usedfor = IBranch
922
923 def checkAuthenticated(self, user):
924- celebs = getUtility(ILaunchpadCelebrities)
925- return (user.inTeam(celebs.admin) or
926- user.inTeam(celebs.bazaar_experts))
927+ return (user.in_admin or
928+ user.in_bazaar_experts)
929
930
931 # Please keep this in sync with AdminPOTemplateDetails. Note that
932@@ -1788,10 +1707,9 @@
933 Any team member can edit a branch subscription for their team.
934 Launchpad Admins can also edit any branch subscription.
935 """
936- celebs = getUtility(ILaunchpadCelebrities)
937 return (user.inTeam(self.obj.person) or
938- user.inTeam(celebs.admin) or
939- user.inTeam(celebs.bazaar_experts))
940+ user.in_admin or
941+ user.in_bazaar_experts)
942
943
944 class BranchSubscriptionView(BranchSubscriptionEdit):
945@@ -1903,13 +1821,12 @@
946 * the reviewer for the target_branch
947 * an administrator
948 """
949- celebs = getUtility(ILaunchpadCelebrities)
950 return (user.inTeam(self.obj.registrant) or
951 user.inTeam(self.obj.source_branch.owner) or
952 user.inTeam(self.obj.target_branch.owner) or
953 user.inTeam(self.obj.target_branch.reviewer) or
954- user.inTeam(celebs.admin) or
955- user.inTeam(celebs.bazaar_experts))
956+ user.in_admin or
957+ user.in_bazaar_experts)
958
959
960 class ViewEntitlement(AuthorizationBase):
961@@ -1927,10 +1844,9 @@
962 Any team member can edit a branch subscription for their team.
963 Launchpad Admins can also edit any branch subscription.
964 """
965- admins = getUtility(ILaunchpadCelebrities).admin
966 return (user.inTeam(self.obj.person) or
967 user.inTeam(self.obj.registrant) or
968- user.inTeam(admins))
969+ user.in_admin)
970
971
972 class AdminDistroSeriesLanguagePacks(
973@@ -1972,8 +1888,7 @@
974 if not self.obj.private:
975 return True
976
977- admins = getUtility(ILaunchpadCelebrities).admin
978- return user.inTeam(self.obj.owner) or user.inTeam(admins)
979+ return user.inTeam(self.obj.owner) or user.in_admin
980
981 def checkUnauthenticated(self):
982 return not self.obj.private
983@@ -1991,8 +1906,7 @@
984
985 def checkAuthenticated(self, user):
986 """We give for now access only to Canonical employees."""
987- hwdb_team = getUtility(ILaunchpadCelebrities).hwdb_team
988- return user.inTeam(hwdb_team)
989+ return user.in_hwdb_team
990
991 def checkUnauthenticated(self):
992 """No access for anonymous users."""
993@@ -2054,9 +1968,7 @@
994 return True
995
996 # Administrator are allowed to view private archives.
997- celebrities = getUtility(ILaunchpadCelebrities)
998- if (user.inTeam(celebrities.admin)
999- or user.inTeam(celebrities.commercial_admin)):
1000+ if user.in_admin or user.in_commercial_admin:
1001 return True
1002
1003 # Owners can view the PPA.
1004@@ -2064,7 +1976,7 @@
1005 return True
1006
1007 # Uploaders can view private PPAs.
1008- if self.obj.is_ppa and self.obj.canUpload(user):
1009+ if self.obj.is_ppa and self.obj.canUpload(user.person):
1010 return True
1011
1012 return False
1013@@ -2096,13 +2008,13 @@
1014 if user.inTeam(self.obj.owner):
1015 return True
1016
1017- if self.obj.is_ppa and self.obj.canUpload(user):
1018+ if self.obj.is_ppa and self.obj.canUpload(user.person):
1019 return True
1020
1021 celebrities = getUtility(ILaunchpadCelebrities)
1022 if (self.obj.is_main and
1023 self.obj.distribution == celebrities.ubuntu and
1024- user.inTeam(celebrities.ubuntu_security)):
1025+ user.in_ubuntu_security):
1026 return True
1027
1028 return False
1029@@ -2118,7 +2030,7 @@
1030 usedfor = IArchiveAuthToken
1031
1032 def checkAuthenticated(self, user):
1033- if user == self.obj.person:
1034+ if user.person == self.obj.person:
1035 return True
1036 auth_edit = EditArchiveAuthToken(self.obj)
1037 return auth_edit.checkAuthenticated(user)
1038@@ -2137,8 +2049,7 @@
1039 auth_append = AppendArchive(self.obj.archive)
1040 if auth_append.checkAuthenticated(user):
1041 return True
1042- admins = getUtility(ILaunchpadCelebrities).admin
1043- return user.inTeam(admins)
1044+ return user.in_admin
1045
1046
1047 class ViewPersonalArchiveSubscription(AuthorizationBase):
1048@@ -2151,15 +2062,14 @@
1049 usedfor = IPersonalArchiveSubscription
1050
1051 def checkAuthenticated(self, user):
1052- if user == self.obj.subscriber:
1053+ if user.person == self.obj.subscriber:
1054 return True
1055 append_archive = AppendArchive(self.obj.archive)
1056
1057 if append_archive.checkAuthenticated(user):
1058 return True
1059
1060- admins = getUtility(ILaunchpadCelebrities).admin
1061- return user.inTeam(admins)
1062+ return user.in_admin
1063
1064
1065 class ViewArchiveSubscriber(AuthorizationBase):
1066@@ -2190,8 +2100,7 @@
1067 auth_append = AppendArchive(self.obj.archive)
1068 if auth_append.checkAuthenticated(user):
1069 return True
1070- admins = getUtility(ILaunchpadCelebrities).admin
1071- return user.inTeam(admins)
1072+ return user.in_admin
1073
1074
1075 class ViewSourcePackagePublishingHistory(AuthorizationBase):
1076@@ -2203,8 +2112,7 @@
1077 view_archive = ViewArchive(self.obj.archive)
1078 if view_archive.checkAuthenticated(user):
1079 return True
1080- admins = getUtility(ILaunchpadCelebrities).admin
1081- return user.inTeam(admins)
1082+ return user.in_admin
1083
1084 def checkUnauthenticated(self):
1085 return not self.obj.archive.private
1086@@ -2262,8 +2170,7 @@
1087 usedfor = IMailingListSet
1088
1089 def checkAuthenticated(self, user):
1090- experts = getUtility(ILaunchpadCelebrities).mailing_list_experts
1091- return user.inTeam(experts)
1092+ return user.in_mailing_list_experts
1093
1094
1095 class ConfigureTeamMailingList(AuthorizationBase):
1096@@ -2284,12 +2191,10 @@
1097 """
1098 # The team owner, the Launchpad mailing list experts and the Launchpad
1099 # administrators can all view a team's +mailinglist page.
1100- celebrities = getUtility(ILaunchpadCelebrities)
1101 team = ITeam(self.obj)
1102- return (
1103- (team is not None and team in user.getAdministratedTeams()) or
1104- user.inTeam(celebrities.admin) or
1105- user.inTeam(celebrities.mailing_list_experts))
1106+ is_team_owner = (
1107+ team is not None and team in user.person.getAdministratedTeams())
1108+ return is_team_owner or user.in_admin or user.in_mailing_list_experts
1109
1110
1111 class ViewEmailAddress(AuthorizationBase):
1112@@ -2319,15 +2224,14 @@
1113 self.obj.person.hide_email_addresses):
1114 return True
1115
1116- user = IPerson(account, None)
1117+ user = IPersonRoles(IPerson(account, None), None)
1118 if user is None:
1119 return False
1120
1121- celebrities = getUtility(ILaunchpadCelebrities)
1122 return (self.obj.person is not None and user.inTeam(self.obj.person)
1123- or user.inTeam(celebrities.commercial_admin)
1124- or user.inTeam(celebrities.registry_experts)
1125- or user.inTeam(celebrities.admin))
1126+ or user.in_commercial_admin
1127+ or user.in_registry_experts
1128+ or user.in_admin)
1129
1130
1131 class EditEmailAddress(EditByOwnersOrAdmins):
1132@@ -2348,10 +2252,7 @@
1133
1134 def checkAuthenticated(self, user):
1135 """Users must be an admin or a member of the tech board."""
1136- celebrities = getUtility(ILaunchpadCelebrities)
1137- return (
1138- user.inTeam(celebrities.admin)
1139- or user.inTeam(celebrities.ubuntu_techboard))
1140+ return user.in_admin or user.in_ubuntu_techboard
1141
1142
1143 class LinkOfficialSourcePackageBranches(AuthorizationBase):
1144@@ -2367,10 +2268,7 @@
1145 return False
1146
1147 def checkAuthenticated(self, user):
1148- celebrities = getUtility(ILaunchpadCelebrities)
1149- return (
1150- user.inTeam(celebrities.ubuntu_branches)
1151- or user.inTeam(celebrities.admin))
1152+ return user.in_ubuntu_branches or user.in_admin
1153
1154
1155 class ChangeOfficialSourcePackageBranchLinks(AuthorizationBase):
1156@@ -2386,10 +2284,7 @@
1157 return False
1158
1159 def checkAuthenticated(self, user):
1160- celebrities = getUtility(ILaunchpadCelebrities)
1161- return (
1162- user.inTeam(celebrities.ubuntu_branches)
1163- or user.inTeam(celebrities.admin))
1164+ return user.in_ubuntu_branches or user.in_admin
1165
1166
1167 class EditPackageset(AuthorizationBase):
1168@@ -2398,10 +2293,7 @@
1169
1170 def checkAuthenticated(self, user):
1171 """The owner of a package set can edit the object."""
1172- celebrities = getUtility(ILaunchpadCelebrities)
1173- return (
1174- user.inTeam(self.obj.owner)
1175- or user.inTeam(celebrities.admin))
1176+ return user.isOwner(self.obj) or user.in_admin
1177
1178
1179 class EditPackagesetSet(AuthorizationBase):
1180@@ -2410,7 +2302,4 @@
1181
1182 def checkAuthenticated(self, user):
1183 """Users must be an admin or a member of the tech board."""
1184- celebrities = getUtility(ILaunchpadCelebrities)
1185- return (
1186- user.inTeam(celebrities.admin)
1187- or user.inTeam(celebrities.ubuntu_techboard))
1188+ return user.in_admin or user.in_ubuntu_techboard
1189
1190=== modified file 'lib/canonical/launchpad/tests/test_personroles.py'
1191--- lib/canonical/launchpad/tests/test_personroles.py 2010-01-08 16:16:50 +0000
1192+++ lib/canonical/launchpad/tests/test_personroles.py 2010-01-15 07:14:13 +0000
1193@@ -103,14 +103,20 @@
1194 roles = IPersonRoles(self.person)
1195 self.assertTrue(roles.isDriver(sprint))
1196
1197- def test_isDriver_multiple_drivers(self):
1198- # The person can be one of multiple drivers of if a product and its
1199- # series each has a driver.
1200+ def test_isOneOfDrivers(self):
1201+ # The person can be one of multiple drivers of if an object
1202+ # implements IHasDrivers.
1203 productseries = self.factory.makeProductSeries()
1204 productseries.product.driver = self.person
1205 productseries.driver = self.factory.makePerson()
1206 roles = IPersonRoles(self.person)
1207- self.assertTrue(roles.isDriver(productseries))
1208+ self.assertTrue(roles.isOneOfDrivers(productseries))
1209+
1210+ def test_isOneOfDrivers_no_drivers(self):
1211+ # If the object does not implement IHasDrivers, False is returned.
1212+ sprint = self.factory.makeSprint()
1213+ roles = IPersonRoles(self.person)
1214+ self.assertFalse(roles.isOneOfDrivers(sprint))
1215
1216 def test_isOneOf(self):
1217 # Objects may have multiple roles that a person can fulfill.
1218
1219=== modified file 'lib/canonical/launchpad/utilities/personroles.py'
1220--- lib/canonical/launchpad/utilities/personroles.py 2010-01-06 14:00:20 +0000
1221+++ lib/canonical/launchpad/utilities/personroles.py 2010-01-15 07:14:13 +0000
1222@@ -9,7 +9,7 @@
1223 from zope.interface import implements
1224 from zope.component import adapts, getUtility
1225 from canonical.launchpad.interfaces import (
1226- ILaunchpadCelebrities, IPersonRoles)
1227+ IHasDrivers, ILaunchpadCelebrities, IPersonRoles)
1228
1229 from lp.registry.interfaces.person import IPerson
1230
1231@@ -26,10 +26,14 @@
1232 def __getattr__(self, name):
1233 """Handle all in_* attributes."""
1234 prefix = 'in_'
1235+ errortext = "'PersonRoles' object has no attribute '%s'" % name
1236 if not name.startswith(prefix):
1237- raise AttributeError
1238+ raise AttributeError(errortext)
1239 attribute = name[len(prefix):]
1240- return self.person.inTeam(getattr(self._celebrities, attribute))
1241+ try:
1242+ return self.person.inTeam(getattr(self._celebrities, attribute))
1243+ except AttributeError:
1244+ raise AttributeError(errortext)
1245
1246 def isOwner(self, obj):
1247 """See IPersonRoles."""
1248@@ -37,10 +41,13 @@
1249
1250 def isDriver(self, obj):
1251 """See IPersonRoles."""
1252- drivers = getattr(obj, 'drivers', None)
1253- if drivers is None:
1254- return self.person.inTeam(obj.driver)
1255- for driver in drivers:
1256+ return self.person.inTeam(obj.driver)
1257+
1258+ def isOneOfDrivers(self, obj):
1259+ """See IPersonRoles."""
1260+ if not IHasDrivers.providedBy(obj):
1261+ return self.isDriver(obj)
1262+ for driver in obj.drivers:
1263 if self.person.inTeam(driver):
1264 return True
1265 return False
1266
1267=== modified file 'lib/lp/code/doc/branch-visibility.txt'
1268--- lib/lp/code/doc/branch-visibility.txt 2009-08-13 15:12:16 +0000
1269+++ lib/lp/code/doc/branch-visibility.txt 2010-01-15 07:14:13 +0000
1270@@ -66,7 +66,7 @@
1271 >>> access = AccessBranch(branch)
1272 >>> access.checkUnauthenticated()
1273 True
1274- >>> access.checkAuthenticated(no_priv_person)
1275+ >>> access.checkAccountAuthenticated(no_priv_person.account)
1276 True
1277
1278 Branches that are private are accessible by the owner and subscribers.
1279@@ -83,7 +83,7 @@
1280 False
1281 >>> branch.owner == no_priv_person
1282 True
1283- >>> access.checkAuthenticated(no_priv_person)
1284+ >>> access.checkAccountAuthenticated(no_priv_person.account)
1285 True
1286
1287 Check the configuration of the AccessBranch authorization.
1288@@ -108,7 +108,7 @@
1289 >>> lp_admins = getUtility(ILaunchpadCelebrities).admin
1290 >>> mark.inTeam(lp_admins)
1291 True
1292- >>> access.checkAuthenticated(mark)
1293+ >>> access.checkAccountAuthenticated(mark.account)
1294 True
1295
1296
1297@@ -125,7 +125,7 @@
1298 True
1299 >>> jdub.inTeam(lp_admins)
1300 False
1301- >>> access.checkAuthenticated(jdub)
1302+ >>> access.checkAccountAuthenticated(jdub.account)
1303 False
1304
1305 Subscribing the Ubuntu team to the branch will allow Jeff to have access
1306@@ -141,7 +141,7 @@
1307 ... CodeReviewNotificationLevel.NOEMAIL)
1308 <BranchSubscription ...>
1309
1310- >>> access.checkAuthenticated(jdub)
1311+ >>> access.checkAccountAuthenticated(jdub.account)
1312 True
1313
1314
1315@@ -153,7 +153,7 @@
1316 >>> ddaa = person_set.getByName('ddaa')
1317 >>> ddaa.inTeam(lp_admins)
1318 False
1319- >>> access.checkAuthenticated(ddaa)
1320+ >>> access.checkAccountAuthenticated(ddaa.account)
1321 False
1322
1323