Merge lp:~stevenk/launchpad/new-branch-visibility into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 15570
Proposed branch: lp:~stevenk/launchpad/new-branch-visibility
Merge into: lp:launchpad
Diff against target: 559 lines (+104/-116)
17 files modified
database/sampledata/current-dev.sql (+1/-0)
database/sampledata/current.sql (+1/-0)
database/schema/security.cfg (+1/-0)
lib/lp/code/browser/tests/test_branch.py (+1/-1)
lib/lp/code/browser/tests/test_branchmergeproposal.py (+3/-2)
lib/lp/code/browser/tests/test_product.py (+5/-4)
lib/lp/code/model/branch.py (+58/-19)
lib/lp/code/model/branchcollection.py (+7/-48)
lib/lp/code/model/tests/test_branchcollection.py (+0/-14)
lib/lp/code/model/tests/test_branchmergeproposal.py (+7/-7)
lib/lp/code/model/tests/test_branchsubscription.py (+1/-1)
lib/lp/code/stories/branches/xx-branch-listings.txt (+7/-6)
lib/lp/code/stories/feeds/xx-branch-atom.txt (+1/-2)
lib/lp/code/tests/test_branch_access_policy_triggers.py (+4/-3)
lib/lp/registry/browser/tests/test_pillar_sharing.py (+3/-4)
lib/lp/registry/stories/product/xx-product-development-focus.txt (+2/-3)
lib/lp/security.py (+2/-2)
To merge this branch: bzr merge lp:~stevenk/launchpad/new-branch-visibility
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+113484@code.launchpad.net

Commit message

Switch BranchCollection.visibleByUser() to using AccessPolicyGrants and AccessArtifactGrants for determining access to a branch, and change IBranch.visibleByUser() to back onto it.

Description of the change

Switch IBranch.visibleByUser() and IBranchCollection.visibleByUser() (sort of), to make use of a new function get_branch_privacy_filter, which backs onto AccessPolicyGrant and AccessArtifactGrant rather than relying on subscriptions to the branch.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'database/sampledata/current-dev.sql'
2--- database/sampledata/current-dev.sql 2012-07-04 22:38:14 +0000
3+++ database/sampledata/current-dev.sql 2012-07-06 13:00:27 +0000
4@@ -3131,6 +3131,7 @@
5 INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (2, 12, 24, '2006-10-16 18:31:43.080236', 1, NULL, 0, 12);
6 INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (4, 64, 29, '2007-05-28 02:41:07.938677', 1, NULL, 0, 64);
7 INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (5, 64, 30, '2007-05-28 02:41:07.938677', 1, NULL, 0, 64);
8+INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (6, 12, 1, '2006-10-16 18:31:43.099585', 1, NULL, 0, 12);
9
10
11 ALTER TABLE branchsubscription ENABLE TRIGGER ALL;
12
13=== modified file 'database/sampledata/current.sql'
14--- database/sampledata/current.sql 2012-07-04 22:38:14 +0000
15+++ database/sampledata/current.sql 2012-07-06 13:00:27 +0000
16@@ -3068,6 +3068,7 @@
17 INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (2, 12, 24, '2006-10-16 18:31:43.080236', 1, NULL, 0, 12);
18 INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (4, 64, 29, '2007-05-28 02:41:07.938677', 1, NULL, 0, 64);
19 INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (5, 64, 30, '2007-05-28 02:41:07.938677', 1, NULL, 0, 64);
20+INSERT INTO branchsubscription (id, person, branch, date_created, notification_level, max_diff_lines, review_level, subscribed_by) VALUES (6, 12, 1, '2006-10-16 18:31:43.099585', 1, NULL, 0, 12);
21
22
23 ALTER TABLE branchsubscription ENABLE TRIGGER ALL;
24
25=== modified file 'database/schema/security.cfg'
26--- database/schema/security.cfg 2012-07-05 10:54:35 +0000
27+++ database/schema/security.cfg 2012-07-06 13:00:27 +0000
28@@ -693,6 +693,7 @@
29 public.accessartifact = SELECT, INSERT, DELETE
30 public.accesspolicy = SELECT
31 public.accesspolicyartifact = SELECT, INSERT, DELETE
32+public.accesspolicygrant = SELECT
33 public.branch = SELECT, INSERT, UPDATE
34 public.branchrevision = SELECT, INSERT
35 public.branchsubscription = SELECT, INSERT
36
37=== modified file 'lib/lp/code/browser/tests/test_branch.py'
38--- lib/lp/code/browser/tests/test_branch.py 2012-06-22 05:52:17 +0000
39+++ lib/lp/code/browser/tests/test_branch.py 2012-07-06 13:00:27 +0000
40@@ -627,7 +627,7 @@
41 with person_logged_in(branch.owner):
42 self.factory.makeBranchMergeProposal(
43 source_branch=branch, target_branch=target_branch,
44- reviewer=private_reviewer)
45+ reviewer=removeSecurityProxy(private_reviewer))
46 return branch
47
48 def test_view_branch_with_private_reviewer(self):
49
50=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
51--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2012-06-08 06:01:50 +0000
52+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2012-07-06 13:00:27 +0000
53@@ -1296,8 +1296,9 @@
54 bmp2 = self.factory.makeBranchMergeProposal(
55 date_created=(
56 datetime(year=2008, month=10, day=10, tzinfo=pytz.UTC)))
57- removeSecurityProxy(bmp2.source_branch).information_type = (
58- InformationType.USERDATA)
59+ removeSecurityProxy(bmp2.source_branch).transitionToInformationType(
60+ InformationType.USERDATA, bmp2.source_branch.owner,
61+ verify_policy=False)
62 self.assertEqual(
63 [bmp1], latest_proposals_for_each_branch([bmp1, bmp2]))
64
65
66=== modified file 'lib/lp/code/browser/tests/test_product.py'
67--- lib/lp/code/browser/tests/test_product.py 2012-05-31 03:54:13 +0000
68+++ lib/lp/code/browser/tests/test_product.py 2012-07-06 13:00:27 +0000
69@@ -112,15 +112,16 @@
70
71 def test_initial_branches_contains_dev_focus_branch(self):
72 product, branch = self.makeProductAndDevelopmentFocusBranch()
73- view = create_initialized_view(product, '+code-index',
74- rootsite='code')
75+ view = create_initialized_view(
76+ product, '+code-index', rootsite='code')
77 self.assertIn(branch, view.initial_branches)
78
79 def test_initial_branches_does_not_contain_private_dev_focus_branch(self):
80 product, branch = self.makeProductAndDevelopmentFocusBranch(
81 information_type=InformationType.USERDATA)
82- view = create_initialized_view(product, '+code-index',
83- rootsite='code')
84+ login(ANONYMOUS)
85+ view = create_initialized_view(
86+ product, '+code-index', rootsite='code')
87 self.assertNotIn(branch, view.initial_branches)
88
89 def test_committer_count_with_revision_authors(self):
90
91=== modified file 'lib/lp/code/model/branch.py'
92--- lib/lp/code/model/branch.py 2012-06-27 22:31:38 +0000
93+++ lib/lp/code/model/branch.py 2012-07-06 13:00:27 +0000
94@@ -7,6 +7,7 @@
95 __all__ = [
96 'Branch',
97 'BranchSet',
98+ 'get_branch_privacy_filter',
99 ]
100
101 from datetime import datetime
102@@ -25,9 +26,11 @@
103 )
104 from storm.expr import (
105 And,
106+ Coalesce,
107 Count,
108 Desc,
109 Insert,
110+ Join,
111 NamedFunc,
112 Not,
113 Or,
114@@ -36,6 +39,7 @@
115 from storm.locals import (
116 AutoReload,
117 Int,
118+ List,
119 Reference,
120 )
121 from storm.store import Store
122@@ -145,7 +149,11 @@
123 validate_person,
124 validate_public_person,
125 )
126-from lp.registry.model.accesspolicy import reconcile_access_for_artifact
127+from lp.registry.model.accesspolicy import (
128+ AccessPolicyGrant,
129+ reconcile_access_for_artifact,
130+ )
131+from lp.registry.model.teammembership import TeamParticipation
132 from lp.services.config import config
133 from lp.services.database.bulk import load_related
134 from lp.services.database.constants import (
135@@ -160,6 +168,10 @@
136 SQLBase,
137 sqlvalues,
138 )
139+from lp.services.database.stormexpr import (
140+ ArrayAgg,
141+ ArrayIntersects,
142+ )
143 from lp.services.helpers import shortlist
144 from lp.services.job.interfaces.job import JobStatus
145 from lp.services.job.model.job import Job
146@@ -188,6 +200,8 @@
147 mirror_status_message = StringCol(default=None)
148 information_type = EnumCol(
149 enum=InformationType, default=InformationType.PUBLIC)
150+ access_policy = IntCol()
151+ access_grants = List(type=Int())
152
153 # These can die after the UI is dropped.
154 @property
155@@ -243,6 +257,15 @@
156 raise BranchCannotBePublic()
157 self.information_type = information_type
158 self._reconcileAccess()
159+ if information_type in PRIVATE_INFORMATION_TYPES:
160+ # Grant the subscriber access if they can't see the branch.
161+ service = getUtility(IService, 'sharing')
162+ blind_subscribers = service.getPeopleWithoutAccess(
163+ self, self.subscribers)
164+ if len(blind_subscribers):
165+ service.ensureAccessGrants(
166+ blind_subscribers, who, branches=[self],
167+ ignore_permissions=True)
168
169 registrant = ForeignKey(
170 dbName='registrant', foreignKey='Person',
171@@ -1257,28 +1280,15 @@
172 job.celeryRunOnCommit()
173 return job
174
175- def _checkBranchVisibleByUser(self, user):
176- """Is *this* branch visible by the user.
177-
178- This method doesn't check the stacked upon branch. That is handled by
179- the `visibleByUser` method.
180- """
181- if self.information_type in PUBLIC_INFORMATION_TYPES:
182- return True
183- if user is None:
184- return False
185- if user.inTeam(self.owner):
186- return True
187- for subscriber in self.subscribers:
188- if user.inTeam(subscriber):
189- return True
190- return user_has_special_branch_access(user)
191-
192 def visibleByUser(self, user, checked_branches=None):
193 """See `IBranch`."""
194 if checked_branches is None:
195 checked_branches = []
196- can_access = self._checkBranchVisibleByUser(user)
197+ if self.information_type in PUBLIC_INFORMATION_TYPES:
198+ can_access = True
199+ else:
200+ can_access = not getUtility(IAllBranches).withIds(
201+ self.id).visibleByUser(user).is_empty()
202 if can_access and self.stacked_on is not None:
203 checked_branches.append(self)
204 if self.stacked_on not in checked_branches:
205@@ -1518,3 +1528,32 @@
206 """
207 update_trigger_modified_fields(branch)
208 send_branch_modified_notifications(branch, event)
209+
210+
211+def get_branch_privacy_filter(user, branch_class=Branch):
212+ public_branch_filter = (
213+ branch_class.information_type.is_in(PUBLIC_INFORMATION_TYPES))
214+
215+ if user is None:
216+ return [public_branch_filter]
217+
218+ artifact_grant_query = Coalesce(
219+ ArrayIntersects(branch_class.access_grants,
220+ Select(
221+ ArrayAgg(TeamParticipation.teamID),
222+ tables=TeamParticipation,
223+ where=(TeamParticipation.person == user)
224+ )), False)
225+
226+ policy_grant_query = branch_class.access_policy.is_in(
227+ Select(
228+ AccessPolicyGrant.policy_id,
229+ tables=(AccessPolicyGrant,
230+ Join(TeamParticipation,
231+ TeamParticipation.teamID ==
232+ AccessPolicyGrant.grantee_id)),
233+ where=(TeamParticipation.person == user)
234+ ))
235+
236+ return [
237+ Or(public_branch_filter, artifact_grant_query, policy_grant_query)]
238
239=== modified file 'lib/lp/code/model/branchcollection.py'
240--- lib/lp/code/model/branchcollection.py 2012-06-06 06:56:17 +0000
241+++ lib/lp/code/model/branchcollection.py 2012-07-06 13:00:27 +0000
242@@ -1,4 +1,4 @@
243-# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
244+# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
245 # GNU Affero General Public License version 3 (see the file LICENSE).
246
247 """Implementations of `IBranchCollection`."""
248@@ -49,7 +49,10 @@
249 from lp.code.interfaces.seriessourcepackagebranch import (
250 IFindOfficialBranchLinks,
251 )
252-from lp.code.model.branch import Branch
253+from lp.code.model.branch import (
254+ Branch,
255+ get_branch_privacy_filter,
256+ )
257 from lp.code.model.branchmergeproposal import BranchMergeProposal
258 from lp.code.model.branchsubscription import BranchSubscription
259 from lp.code.model.codeimport import CodeImport
260@@ -787,7 +790,6 @@
261 asymmetric_filter_expressions=asymmetric_filter_expressions,
262 asymmetric_tables=asymmetric_tables)
263 self._user = user
264- self._private_branch_ids = self._getPrivateBranchSubQuery()
265
266 def _filterBy(self, expressions, table=None, join=None,
267 exclude_from_search=None, symmetric=True):
268@@ -829,57 +831,14 @@
269 asymmetric_expr,
270 asymmetric_tables)
271
272- def _getPrivateBranchSubQuery(self):
273- """Return a subquery to get the private branches the user can see.
274-
275- If the user is None (which is used for anonymous access), then there
276- is no subquery. Otherwise return the branch ids for the private
277- branches that the user owns or is subscribed to.
278- """
279- # Everyone can see public branches.
280- person = self._user
281- if person is None:
282- # Anonymous users can only see the public branches.
283- return None
284-
285- # A union is used here rather than the more simplistic simple joins
286- # due to the query plans generated. If we just have a simple query
287- # then we are joining across TeamParticipation and BranchSubscription.
288- # This creates a bad plan, hence the use of a union.
289- private_branches = Union(
290- # Private branches the person owns (or a team the person is in).
291- Select(Branch.id,
292- And(Branch.owner == TeamParticipation.teamID,
293- TeamParticipation.person == person,
294- Branch.information_type.is_in(
295- PRIVATE_INFORMATION_TYPES))),
296- # Private branches the person is subscribed to, either directly or
297- # indirectly.
298- Select(Branch.id,
299- And(BranchSubscription.branch == Branch.id,
300- BranchSubscription.person ==
301- TeamParticipation.teamID,
302- TeamParticipation.person == person,
303- Branch.information_type.is_in(
304- PRIVATE_INFORMATION_TYPES))))
305- return private_branches
306-
307 def _getBranchVisibilityExpression(self, branch_class=Branch):
308 """Return the where clauses for visibility.
309
310 :param branch_class: The Branch class to use - permits using
311 ClassAliases.
312 """
313- public_branches = branch_class.information_type.is_in(
314- PUBLIC_INFORMATION_TYPES)
315- if self._private_branch_ids is None:
316- # Public only.
317- return [public_branches]
318- else:
319- public_or_private = Or(
320- public_branches,
321- branch_class.id.is_in(self._private_branch_ids))
322- return [public_or_private]
323+ return get_branch_privacy_filter(
324+ self._user, branch_class=branch_class)
325
326 def _getCandidateBranchesWith(self):
327 """Return WITH clauses defining candidate branches.
328
329=== modified file 'lib/lp/code/model/tests/test_branchcollection.py'
330--- lib/lp/code/model/tests/test_branchcollection.py 2012-06-11 10:25:46 +0000
331+++ lib/lp/code/model/tests/test_branchcollection.py 2012-07-06 13:00:27 +0000
332@@ -636,20 +636,6 @@
333 sorted([self.public_branch, self.private_branch1]),
334 sorted(branches.getBranches()))
335
336- def test_owner_member_sees_own_branches(self):
337- # Members of teams that own branches can see branches owned by those
338- # teams, as well as public branches.
339- team_owner = self.factory.makePerson()
340- team = self.factory.makeTeam(team_owner)
341- private_branch = self.factory.makeAnyBranch(
342- owner=team, stacked_on=self.private_stacked_on_branch,
343- name='team')
344- removeSecurityProxy(private_branch).unsubscribe(team, team_owner)
345- branches = self.all_branches.visibleByUser(team_owner)
346- self.assertEqual(
347- sorted([self.public_branch, private_branch]),
348- sorted(branches.getBranches()))
349-
350 def test_launchpad_services_sees_all(self):
351 # The LAUNCHPAD_SERVICES special user sees *everything*.
352 branches = self.all_branches.visibleByUser(LAUNCHPAD_SERVICES)
353
354=== modified file 'lib/lp/code/model/tests/test_branchmergeproposal.py'
355--- lib/lp/code/model/tests/test_branchmergeproposal.py 2012-06-11 10:25:46 +0000
356+++ lib/lp/code/model/tests/test_branchmergeproposal.py 2012-07-06 13:00:27 +0000
357@@ -166,7 +166,7 @@
358 product=product)
359 with person_logged_in(owner):
360 trunk.reviewer = team
361- bmp = self.factory.makeBranchMergeProposal(
362+ self.factory.makeBranchMergeProposal(
363 source_branch=branch, target_branch=trunk)
364 subscriptions = [bsub.person for bsub in branch.subscriptions]
365 self.assertEqual([owner], subscriptions)
366@@ -183,7 +183,7 @@
367 product=product)
368 with person_logged_in(owner):
369 trunk.reviewer = team
370- bmp = self.factory.makeBranchMergeProposal(
371+ self.factory.makeBranchMergeProposal(
372 source_branch=branch, target_branch=trunk)
373 subscriptions = [bsub.person for bsub in branch.subscriptions]
374 self.assertContentEqual([owner, team], subscriptions)
375@@ -967,13 +967,13 @@
376 CodeReviewNotificationLevel.FULL, charlie)
377 # Make both branches private.
378 for branch in (bmp.source_branch, bmp.target_branch):
379- removeSecurityProxy(branch).information_type = (
380- InformationType.USERDATA)
381+ removeSecurityProxy(branch).transitionToInformationType(
382+ InformationType.USERDATA, branch.owner, verify_policy=False)
383 recipients = bmp.getNotificationRecipients(
384 CodeReviewNotificationLevel.FULL)
385- self.assertFalse(bob in recipients)
386- self.assertFalse(eric in recipients)
387- self.assertTrue(charlie in recipients)
388+ self.assertNotIn(bob, recipients)
389+ self.assertNotIn(eric, recipients)
390+ self.assertIn(charlie, recipients)
391
392
393 class TestGetAddress(TestCaseWithFactory):
394
395=== modified file 'lib/lp/code/model/tests/test_branchsubscription.py'
396--- lib/lp/code/model/tests/test_branchsubscription.py 2012-06-27 22:31:38 +0000
397+++ lib/lp/code/model/tests/test_branchsubscription.py 2012-07-06 13:00:27 +0000
398@@ -95,7 +95,7 @@
399 None, CodeReviewNotificationLevel.NOEMAIL, owner)
400 self.assertTrue(branch.visibleByUser(subscribee))
401
402- def test_unsubscribe_gives_access(self):
403+ def test_unsubscribe_removes_access(self):
404 """Unsubscibing a user to a branch removes their access."""
405 owner = self.factory.makePerson()
406 branch = self.factory.makeBranch(
407
408=== modified file 'lib/lp/code/stories/branches/xx-branch-listings.txt'
409--- lib/lp/code/stories/branches/xx-branch-listings.txt 2012-06-22 05:52:17 +0000
410+++ lib/lp/code/stories/branches/xx-branch-listings.txt 2012-07-06 13:00:27 +0000
411@@ -25,7 +25,7 @@
412 >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
413 >>> print links.renderContents()
414 <BLANKLINE>
415- ...1...&rarr;...6...of 10 results...
416+ ...1...&rarr;...6...of 9 results...
417
418 >>> table = find_tag_by_id(browser.contents, 'branchtable')
419 >>> for row in table.thead.fetch('tr'):
420@@ -52,13 +52,12 @@
421 >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
422 >>> print links.renderContents()
423 <BLANKLINE>
424- ...7...&rarr;...10...of 10 results...
425+ ...7...&rarr;...9...of 9 results...
426
427 >>> table = find_tag_by_id(browser.contents, 'branchtable')
428 >>> for row in table.tbody.fetch('tr'):
429 ... print extract_text(row)
430 lp://dev/~name12/gnome-terminal/klingon Experimental ...
431- lp://dev/~name12/landscape/feature-x Development ...
432 lp://dev/~name12/+junk/junk.contrib Development ...
433 lp://dev/~name12/+junk/junk.dev Experimental ...
434
435@@ -113,7 +112,7 @@
436 >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
437 >>> print links.renderContents()
438 <BLANKLINE>
439- ...1...&rarr;...6...of 12 results...
440+ ...1...&rarr;...6...of 11 results...
441
442 >>> table = find_tag_by_id(browser.contents, 'branchtable')
443 >>> for row in table.tbody.fetch('tr'):
444@@ -129,7 +128,7 @@
445 >>> links = find_tag_by_id(browser.contents, 'branch-batch-links')
446 >>> print links.renderContents()
447 <BLANKLINE>
448- ...7...&rarr;...12...of 12 results...
449+ ...7...&rarr;...11...of 11 results...
450
451 >>> table = find_tag_by_id(browser.contents, 'branchtable')
452 >>> for row in table.tbody.fetch('tr'):
453@@ -137,7 +136,8 @@
454 lp://dev/~name12/gnome-terminal/pushed Development ...
455 lp://dev/~name12/gnome-terminal/scanned Development ...
456 lp://dev/~name12/gnome-terminal/klingon Experimental ...
457- lp://dev/~name12/landscape/feature-x Development ...
458+ lp://dev/~name12/+junk/junk.contrib Development ...
459+ lp://dev/~name12/+junk/junk.dev Experimental ...
460
461
462 Selecting an individual lifecycle status from the select control
463@@ -186,6 +186,7 @@
464 >>> table = find_tag_by_id(browser.contents, 'branchtable')
465 >>> for row in table.tbody.fetch('tr'):
466 ... print extract_text(row)
467+ lp://dev/~name12/firefox/main ...
468 lp://dev/~launchpad/gnome-terminal/launchpad ...
469 lp://dev/~name12/+junk/junk.dev ...
470
471
472=== modified file 'lib/lp/code/stories/feeds/xx-branch-atom.txt'
473--- lib/lp/code/stories/feeds/xx-branch-atom.txt 2011-12-30 06:14:56 +0000
474+++ lib/lp/code/stories/feeds/xx-branch-atom.txt 2012-07-06 13:00:27 +0000
475@@ -102,8 +102,7 @@
476 >>> from zope.component import getUtility
477 >>> from zope.security.proxy import removeSecurityProxy
478 >>> from lp.code.model.branch import Branch
479- >>> from lp.code.interfaces.branchcollection import (
480- ... IAllBranches)
481+ >>> from lp.code.interfaces.branchcollection import IAllBranches
482 >>> from lp.registry.interfaces.person import IPersonSet
483 >>> login(ANONYMOUS)
484 >>> person_set = getUtility(IPersonSet)
485
486=== modified file 'lib/lp/code/tests/test_branch_access_policy_triggers.py'
487--- lib/lp/code/tests/test_branch_access_policy_triggers.py 2012-06-15 06:38:35 +0000
488+++ lib/lp/code/tests/test_branch_access_policy_triggers.py 2012-07-06 13:00:27 +0000
489@@ -32,9 +32,10 @@
490
491 def test_adding_aag_with_private_branch(self):
492 # Adding a new AAG updates the branch columns via trigger.
493+ owner = self.factory.makePerson()
494 branch = self.factory.makeBranch(
495- information_type=InformationType.USERDATA)
496- self.assertAccess(branch, 65, [])
497+ information_type=InformationType.USERDATA, owner=owner)
498+ self.assertAccess(branch, 65, [owner.id])
499 artifact = self.factory.makeAccessArtifact(concrete=branch)
500 grant = self.factory.makeAccessArtifactGrant(artifact=artifact)
501- self.assertAccess(branch, 65, [grant.grantee.id])
502+ self.assertAccess(branch, 65, [owner.id, grant.grantee.id])
503
504=== modified file 'lib/lp/registry/browser/tests/test_pillar_sharing.py'
505--- lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-06-28 15:48:42 +0000
506+++ lib/lp/registry/browser/tests/test_pillar_sharing.py 2012-07-06 13:00:27 +0000
507@@ -78,9 +78,8 @@
508 self.factory.makeAccessPolicyGrant(self.access_policy, grantee)
509 return grantee
510
511- def makeArtifactGrantee(
512- self, grantee=None, with_bug=True,
513- with_branch=False, security=False):
514+ def makeArtifactGrantee(self, grantee=None, with_bug=True,
515+ with_branch=False, security=False):
516 if grantee is None:
517 grantee = self.factory.makePerson()
518
519@@ -242,7 +241,7 @@
520 IStore(self.pillar).invalidate()
521 with StormStatementRecorder() as recorder:
522 create_initialized_view(pillarperson, '+index')
523- self.assertThat(recorder, HasQueryCount(LessThan(12)))
524+ self.assertThat(recorder, HasQueryCount(LessThan(26)))
525
526 def test_view_write_enabled_without_feature_flag(self):
527 # Test that sharing_write_enabled is not set without the feature flag.
528
529=== modified file 'lib/lp/registry/stories/product/xx-product-development-focus.txt'
530--- lib/lp/registry/stories/product/xx-product-development-focus.txt 2012-06-15 13:56:29 +0000
531+++ lib/lp/registry/stories/product/xx-product-development-focus.txt 2012-07-06 13:00:27 +0000
532@@ -146,10 +146,9 @@
533 appears as if there is no series branch set.
534
535 >>> login('admin@canonical.com')
536- >>> from zope.security.proxy import removeSecurityProxy
537 >>> from lp.registry.enums import InformationType
538- >>> removeSecurityProxy(branch).information_type = (
539- ... InformationType.USERDATA)
540+ >>> branch.transitionToInformationType(
541+ ... InformationType.USERDATA, branch.owner, verify_policy=False)
542 >>> logout()
543
544 >>> anon_browser.open('http://launchpad.dev/fooix')
545
546=== modified file 'lib/lp/security.py'
547--- lib/lp/security.py 2012-06-28 01:14:33 +0000
548+++ lib/lp/security.py 2012-07-06 13:00:27 +0000
549@@ -2022,8 +2022,8 @@
550 """Controls visibility of branches.
551
552 A person can see the branch if the branch is public, they are the owner
553- of the branch, they are in the team that owns the branch, subscribed to
554- the branch, or a launchpad administrator.
555+ of the branch, they are in the team that owns the branch, they have an
556+ access grant to the branch, or a launchpad administrator.
557 """
558 permission = 'launchpad.View'
559 usedfor = IBranch