Merge lp:~stevenk/launchpad/teach-rasj-about-branches into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 15601
Proposed branch: lp:~stevenk/launchpad/teach-rasj-about-branches
Merge into: lp:launchpad
Diff against target: 257 lines (+147/-18)
2 files modified
lib/lp/registry/model/sharingjob.py (+63/-17)
lib/lp/registry/tests/test_sharingjob.py (+84/-1)
To merge this branch: bzr merge lp:~stevenk/launchpad/teach-rasj-about-branches
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+114106@code.launchpad.net

Commit message

Teach RemoveArtifactSubscriptionsJob to search for inaccessible branches and also remove subscribers, like it does for bugs.

Description of the change

Teach RemoveArtifactSubscriptionsJob about branches.

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

51 @property
52 + def branch_ids(self):
53 + if not 'branch_ids' in self.metadata:
54 + return []
55 + return self.metadata['branch_ids']

Isn't that equivalent to "return self.metadata.get('branch_ids', [])"?

We really need to rearchitect the tests for that job, but I guess it's OK for now. Otherwise this looks good, thanks.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/registry/model/sharingjob.py'
--- lib/lp/registry/model/sharingjob.py 2012-06-29 02:27:31 +0000
+++ lib/lp/registry/model/sharingjob.py 2012-07-11 01:27:22 +0000
@@ -41,10 +41,20 @@
41 implements,41 implements,
42 )42 )
4343
44from lp.bugs.interfaces.bug import IBugSet44from lp.bugs.interfaces.bug import (
45 IBug,
46 IBugSet,
47 )
45from lp.bugs.model.bugsubscription import BugSubscription48from lp.bugs.model.bugsubscription import BugSubscription
46from lp.bugs.model.bugtaskflat import BugTaskFlat49from lp.bugs.model.bugtaskflat import BugTaskFlat
47from lp.bugs.model.bugtasksearch import get_bug_privacy_filter_terms50from lp.bugs.model.bugtasksearch import get_bug_privacy_filter_terms
51from lp.code.interfaces.branch import IBranch
52from lp.code.interfaces.branchlookup import IBranchLookup
53from lp.code.model.branch import (
54 Branch,
55 get_branch_privacy_filter,
56 )
57from lp.code.model.branchsubscription import BranchSubscription
48from lp.registry.enums import InformationType58from lp.registry.enums import InformationType
49from lp.registry.interfaces.person import IPersonSet59from lp.registry.interfaces.person import IPersonSet
50from lp.registry.interfaces.product import IProduct60from lp.registry.interfaces.product import IProduct
@@ -253,12 +263,20 @@
253 information_types=None):263 information_types=None):
254 """See `IRemoveArtifactSubscriptionsJob`."""264 """See `IRemoveArtifactSubscriptionsJob`."""
255265
256 bug_ids = [bug.id for bug in artifacts or []]266 bug_ids = []
267 branch_ids = []
268 if artifacts:
269 for artifact in artifacts:
270 if IBug.providedBy(artifact):
271 bug_ids.append(artifact.id)
272 elif IBranch.providedBy(artifact):
273 branch_ids.append(artifact.id)
257 information_types = [274 information_types = [
258 info_type.value for info_type in information_types or []275 info_type.value for info_type in information_types or []
259 ]276 ]
260 metadata = {277 metadata = {
261 'bug_ids': bug_ids,278 'bug_ids': bug_ids,
279 'branch_ids': branch_ids,
262 'information_types': information_types,280 'information_types': information_types,
263 'requestor.id': requestor.id281 'requestor.id': requestor.id
264 }282 }
@@ -275,15 +293,21 @@
275293
276 @property294 @property
277 def bug_ids(self):295 def bug_ids(self):
278 if not 'bug_ids' in self.metadata:296 return self.metadata.get('bug_ids', [])
279 return []
280 return self.metadata['bug_ids']
281297
282 @property298 @property
283 def bugs(self):299 def bugs(self):
284 return getUtility(IBugSet).getByNumbers(self.bug_ids)300 return getUtility(IBugSet).getByNumbers(self.bug_ids)
285301
286 @property302 @property
303 def branch_ids(self):
304 return self.metadata.get('branch_ids', [])
305
306 @property
307 def branches(self):
308 return [getUtility(IBranchLookup).get(id) for id in self.branch_ids]
309
310 @property
287 def information_types(self):311 def information_types(self):
288 if not 'information_types' in self.metadata:312 if not 'information_types' in self.metadata:
289 return []313 return []
@@ -307,6 +331,7 @@
307 'information_types': [t.name for t in self.information_types],331 'information_types': [t.name for t in self.information_types],
308 'requestor': self.requestor.name,332 'requestor': self.requestor.name,
309 'bug_ids': self.bug_ids,333 'bug_ids': self.bug_ids,
334 'branch_ids': self.branch_ids,
310 'pillar': getattr(self.pillar, 'name', None),335 'pillar': getattr(self.pillar, 'name', None),
311 'grantee': getattr(self.grantee, 'name', None)336 'grantee': getattr(self.grantee, 'name', None)
312 }337 }
@@ -321,33 +346,54 @@
321346
322 # Find all bug subscriptions for which the subscriber cannot see the347 # Find all bug subscriptions for which the subscriber cannot see the
323 # bug.348 # bug.
324 invisible_filter = (349 bug_invisible_filter = Not(
325 Not(Or(*get_bug_privacy_filter_terms(BugSubscription.person_id))))350 Or(*get_bug_privacy_filter_terms(BugSubscription.person_id)))
326 filters = [invisible_filter]351 bug_filters = [bug_invisible_filter]
352 branch_invisible_filter = Not(
353 Or(*get_branch_privacy_filter(BranchSubscription.personID)))
354 branch_filters = [branch_invisible_filter]
327355
328 if self.bug_ids:356 if self.bug_ids:
329 filters.append(BugTaskFlat.bug_id.is_in(self.bug_ids))357 bug_filters.append(BugTaskFlat.bug_id.is_in(self.bug_ids))
358 elif self.branch_ids:
359 branch_filters.append(Branch.id.is_in(self.branch_ids))
330 else:360 else:
331 if self.information_types:361 if self.information_types:
332 filters.append(362 bug_filters.append(
333 BugTaskFlat.information_type.is_in(self.information_types))363 BugTaskFlat.information_type.is_in(
364 self.information_types))
365 branch_filters.append(
366 Branch.information_type.is_in(self.information_types))
334 if self.product:367 if self.product:
335 filters.append(368 bug_filters.append(
336 BugTaskFlat.product == self.product)369 BugTaskFlat.product == self.product)
370 branch_filters.append(Branch.product == self.product)
337 if self.distro:371 if self.distro:
338 filters.append(372 bug_filters.append(
339 BugTaskFlat.distribution == self.distro)373 BugTaskFlat.distribution == self.distro)
374 branch_filters.append(Branch.distribution == self.distro)
340375
341 if self.grantee:376 if self.grantee:
342 filters.append(377 bug_filters.append(
343 In(BugSubscription.person_id,378 In(BugSubscription.person_id,
344 Select(379 Select(
345 TeamParticipation.personID,380 TeamParticipation.personID,
346 where=TeamParticipation.team == self.grantee)))381 where=TeamParticipation.team == self.grantee)))
347 subscriptions = IStore(BugSubscription).using(382 branch_filters.append(
383 In(BranchSubscription.personID,
384 Select(
385 TeamParticipation.personID,
386 where=TeamParticipation.team == self.grantee)))
387
388 bug_subscriptions = IStore(BugSubscription).using(
348 BugSubscription,389 BugSubscription,
349 Join(BugTaskFlat, BugTaskFlat.bug_id == BugSubscription.bug_id)390 Join(BugTaskFlat, BugTaskFlat.bug_id == BugSubscription.bug_id)
350 ).find(BugSubscription, *filters).config(distinct=True)391 ).find(BugSubscription, *bug_filters).config(distinct=True)
351 for sub in subscriptions:392 branch_subscriptions = IStore(BranchSubscription).find(
393 BranchSubscription, *branch_filters).config(distinct=True)
394 for sub in bug_subscriptions:
352 sub.bug.unsubscribe(395 sub.bug.unsubscribe(
353 sub.person, self.requestor, ignore_permissions=True)396 sub.person, self.requestor, ignore_permissions=True)
397 for sub in branch_subscriptions:
398 sub.branch.unsubscribe(
399 sub.person, self.requestor, ignore_permissions=True)
354400
=== modified file 'lib/lp/registry/tests/test_sharingjob.py'
--- lib/lp/registry/tests/test_sharingjob.py 2012-06-29 02:15:05 +0000
+++ lib/lp/registry/tests/test_sharingjob.py 2012-07-11 01:27:22 +0000
@@ -101,7 +101,7 @@
101 self.requestor, artifacts=[self.bug])101 self.requestor, artifacts=[self.bug])
102 return job102 return job
103103
104 def test_repr(self):104 def test_repr_bugs(self):
105 job = self._makeJob()105 job = self._makeJob()
106 self.assertEqual(106 self.assertEqual(
107 '<REMOVE_ARTIFACT_SUBSCRIPTIONS job reconciling subscriptions '107 '<REMOVE_ARTIFACT_SUBSCRIPTIONS job reconciling subscriptions '
@@ -109,6 +109,16 @@
109 % (self.bug.id, self.requestor.name),109 % (self.bug.id, self.requestor.name),
110 repr(job))110 repr(job))
111111
112 def test_repr_branches(self):
113 requestor = self.factory.makePerson()
114 branch = self.factory.makeBranch()
115 job = getUtility(IRemoveArtifactSubscriptionsJobSource).create(
116 requestor, artifacts=[branch])
117 self.assertEqual(
118 '<REMOVE_ARTIFACT_SUBSCRIPTIONS job reconciling subscriptions '
119 'for branch_ids=[%d], requestor=%s>'
120 % (branch.id, requestor.name), repr(job))
121
112 def test_create_success(self):122 def test_create_success(self):
113 # Create an instance of SharingJobDerived that delegates to SharingJob.123 # Create an instance of SharingJobDerived that delegates to SharingJob.
114 self.assertIs(True, ISharingJobSource.providedBy(SharingJobDerived))124 self.assertIs(True, ISharingJobSource.providedBy(SharingJobDerived))
@@ -323,6 +333,79 @@
323 self.assertIn(artifact_team_grantee, subscribers)333 self.assertIn(artifact_team_grantee, subscribers)
324 self.assertIn(artifact_indirect_grantee, subscribers)334 self.assertIn(artifact_indirect_grantee, subscribers)
325335
336 def _assert_branch_change_unsubscribes(self, change_callback):
337 product = self.factory.makeProduct()
338 owner = self.factory.makePerson()
339 [policy] = getUtility(IAccessPolicySource).find(
340 [(product, InformationType.USERDATA)])
341 # The policy grantees will lose access.
342 policy_indirect_grantee = self.factory.makePerson()
343 policy_team_grantee = self.factory.makeTeam(
344 subscription_policy=TeamSubscriptionPolicy.RESTRICTED,
345 members=[policy_indirect_grantee])
346
347 self.factory.makeAccessPolicyGrant(policy, policy_team_grantee, owner)
348 login_person(owner)
349 branch = self.factory.makeBranch(
350 owner=owner, product=product,
351 information_type=InformationType.USERDATA)
352
353 # The artifact grantees will not lose access when the job is run.
354 artifact_indirect_grantee = self.factory.makePerson()
355 artifact_team_grantee = self.factory.makeTeam(
356 subscription_policy=TeamSubscriptionPolicy.RESTRICTED,
357 members=[artifact_indirect_grantee])
358
359 branch.subscribe(
360 policy_team_grantee, BranchSubscriptionNotificationLevel.NOEMAIL,
361 None, CodeReviewNotificationLevel.NOEMAIL, owner)
362 branch.subscribe(
363 policy_indirect_grantee,
364 BranchSubscriptionNotificationLevel.NOEMAIL, None,
365 CodeReviewNotificationLevel.NOEMAIL, owner)
366 branch.subscribe(
367 artifact_team_grantee,
368 BranchSubscriptionNotificationLevel.NOEMAIL, None,
369 CodeReviewNotificationLevel.NOEMAIL, owner)
370 branch.subscribe(
371 artifact_indirect_grantee,
372 BranchSubscriptionNotificationLevel.NOEMAIL, None,
373 CodeReviewNotificationLevel.NOEMAIL, owner)
374 # Subscribing policy_team_grantee has created an artifact grant so we
375 # need to revoke that to test the job.
376 getUtility(IAccessArtifactGrantSource).revokeByArtifact(
377 getUtility(IAccessArtifactSource).find(
378 [branch]), [policy_team_grantee])
379
380 # policy grantees are subscribed because the job has not been run yet.
381 #subscribers = removeSecurityProxy(branch).subscribers
382 self.assertIn(policy_team_grantee, branch.subscribers)
383 self.assertIn(policy_indirect_grantee, branch.subscribers)
384
385 # Change branch attributes so that it can become inaccessible for
386 # some users.
387 change_callback(branch)
388 reconcile_access_for_artifact(
389 branch, branch.information_type, [branch.product])
390
391 getUtility(IRemoveArtifactSubscriptionsJobSource).create(
392 owner, [branch])
393 with block_on_job(self):
394 transaction.commit()
395
396 # Check the result. Policy grantees will be unsubscribed.
397 self.assertNotIn(policy_team_grantee, branch.subscribers)
398 self.assertNotIn(policy_indirect_grantee, branch.subscribers)
399 self.assertIn(artifact_team_grantee, branch.subscribers)
400 self.assertIn(artifact_indirect_grantee, branch.subscribers)
401
402 def test_change_information_type_branch(self):
403 def change_information_type(branch):
404 removeSecurityProxy(branch).information_type = (
405 InformationType.EMBARGOEDSECURITY)
406
407 self._assert_branch_change_unsubscribes(change_information_type)
408
326 def test_change_information_type(self):409 def test_change_information_type(self):
327 # Changing the information type of a bug unsubscribes users who can no410 # Changing the information type of a bug unsubscribes users who can no
328 # longer see the bug.411 # longer see the bug.