Merge lp:~henninge/launchpad/bug-503454-security-py into lp:launchpad
- bug-503454-security-py
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Edwin Grubbs |
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Edwin Grubbs (community) | code | Approve | |
Review via email: mp+17241@code.launchpad.net |
Commit message
Updated security.py to use PersonRoles. Added doctest for PersonRoles.
Description of the change
Henning Eggers (henninge) wrote : | # |
Henning Eggers (henninge) wrote : | # |
Found room for a little more improvement. I'd better stop now, though. ;-)
Edwin Grubbs (edwin-grubbs) wrote : | # |
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.
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/
>--- lib/canonical/
>+++ lib/canonical/
>@@ -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 ILaunchpadCeleb
>+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.
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.
>+ >>> person = factory.
>+ >>> print IPersonRoles(
>+ <canonical.
>+
>+The original Person object can be reached through the person attribute.
>+
>+ >>> roles = IPersonRoles(
>+ >>> print roles.person is person
>+ True
>+
>+
>+== Celebrity persons ==
>+
>+There are a number of celebrity persons defined in ILaunchpadCeleb
>+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.
>+ ... ILaunchpadCeleb
>+ >>> rosetta_experts = getUtility(
>+ >>> print person.
>+ False
>+
>+ >>> print roles.in_
>+ False
>+
>+The tes...
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.
> 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
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 |
= 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 "checkAuthentic ated" 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 "checkAuthentic ated" on an object that implements "IAuthorization". "checkAuthentic ated" has been replaced by "checkAccountAu thenticated" 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 checkAccountAut henticated.
* 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: AuthorizationBa se.checkAccount Authenticated applies the IPersonRoles adapter to the IPerson object which it derives from the account. So unless checkAccountAut henticated gets overwritten, checkAuthenticated reveives an IPersonRoles object instead of an IPerson object. celebrity. some_celeb) with user.in_some_celeb.
* Replaced all calls to user.inTeam(
* 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 checkAccountAut henticated.
== 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: /launchpad/ security. py /launchpad/ doc/hasowne. ..
lib/canonical
lib/canonical