Merge lp:~jcsackett/launchpad/404-project-milestones-privacy into lp:launchpad

Proposed by j.c.sackett on 2012-11-20
Status: Merged
Approved by: j.c.sackett on 2012-11-21
Approved revision: no longer in the source branch.
Merged at revision: 16296
Proposed branch: lp:~jcsackett/launchpad/404-project-milestones-privacy
Merge into: lp:launchpad
Diff against target: 82 lines (+42/-2)
2 files modified
lib/lp/registry/browser/tests/test_projectgroup.py (+39/-1)
lib/lp/registry/model/projectgroup.py (+3/-1)
To merge this branch: bzr merge lp:~jcsackett/launchpad/404-project-milestones-privacy
Reviewer Review Type Date Requested Status
Deryck Hodge (community) 2012-11-20 Approve on 2012-11-20
Review via email: mp+135252@code.launchpad.net

Commit Message

Fixes ProjectMilestone generation in the milestone page to not link private products for unpriveleged users.

Description of the Change

Summary
=======
Going to a projectmilestone index page causes a 403 when the milestone
incorporates data from private products.

This is because product and milestone data isn't sufficiently filtered. While
the initial query to fetch all milestones on a project's associated products
filters, a second query is made to group the milestones appropriated and
combine the data for product milestones with the same name. This second a
query is not filtered, and should be.

Preimp
======
Spoke with Curtis Hovey about the initial problem.

Implementation
==============
Add the privacy filter to the second query.

Tests
=====
bin/test -vvct test_mixed_product_projectgroup_milestone

QA
==
QA steps are listed in a comment by Curtis Hovey on the bug.

LoC
===
Part of private projects.

Lint
====

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/registry/model/projectgroup.py
  lib/lp/registry/browser/tests/test_projectgroup.py

To post a comment you must log in.
Deryck Hodge (deryck) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/tests/test_projectgroup.py'
2--- lib/lp/registry/browser/tests/test_projectgroup.py 2012-10-19 14:22:36 +0000
3+++ lib/lp/registry/browser/tests/test_projectgroup.py 2012-11-21 00:15:24 +0000
4@@ -15,7 +15,10 @@
5 from lp.app.browser.lazrjs import vocabulary_to_choice_edit_items
6 from lp.app.enums import InformationType
7 from lp.registry.browser.tests.test_product import make_product_form
8-from lp.registry.enums import EXCLUSIVE_TEAM_POLICY
9+from lp.registry.enums import (
10+ EXCLUSIVE_TEAM_POLICY,
11+ TeamMembershipPolicy,
12+ )
13 from lp.registry.interfaces.person import IPersonSet
14 from lp.registry.interfaces.product import IProductSet
15 from lp.services.features.testing import FeatureFixture
16@@ -96,6 +99,41 @@
17 self.assertNotIn(product_name, browser.contents)
18 self.assertIn(public_product.displayname, browser.contents)
19
20+ def test_mixed_product_projectgroup_milestone(self):
21+ # If a milestone is mixed between public and proprietary products,
22+ # only the public is shown to people without access.
23+ self.useFixture(
24+ FeatureFixture({u'disclosure.private_projects.enabled': u'on'}))
25+ owner = self.factory.makePerson()
26+ teammember = self.factory.makePerson()
27+ owning_team = self.factory.makeTeam(owner=owner,
28+ membership_policy=TeamMembershipPolicy.RESTRICTED)
29+ with person_logged_in(owner):
30+ owning_team.addMember(teammember, owner)
31+ group = self.factory.makeProject(owner=owning_team)
32+ private = self.factory.makeProduct(
33+ project=group, owner=owner,
34+ information_type=InformationType.PROPRIETARY, name='private')
35+ public = self.factory.makeProduct(
36+ project=group, owner=owner, name='public')
37+ private_milestone = self.factory.makeMilestone(
38+ product=private, name='1.0')
39+ public_milestone = self.factory.makeMilestone(
40+ product=public, name='1.0')
41+ with person_logged_in(owner):
42+ self.factory.makeBug(
43+ target=private, owner=owner, milestone=private_milestone,
44+ title='This is the private bug')
45+ self.factory.makeBug(
46+ target=public, owner=owner, milestone=public_milestone,
47+ title='This is the public bug')
48+
49+ group_milestone = group.milestones[0]
50+ browser = self.getViewBrowser(
51+ group_milestone, user=self.factory.makePerson())
52+ self.assertTrue("This is the public bug" in browser.contents)
53+ self.assertFalse("This is the private bug" in browser.contents)
54+
55
56 class TestProjectGroupEditView(TestCaseWithFactory):
57 """Tests the edit view."""
58
59=== modified file 'lib/lp/registry/model/projectgroup.py'
60--- lib/lp/registry/model/projectgroup.py 2012-11-15 22:23:08 +0000
61+++ lib/lp/registry/model/projectgroup.py 2012-11-21 00:15:24 +0000
62@@ -430,10 +430,11 @@
63 SQL('MIN(Milestone.dateexpected)'),
64 SQL('BOOL_OR(Milestone.active)'),
65 )
66+ privacy_filter = ProductSet.getProductPrivacyFilter(user)
67 conditions = And(Milestone.product == Product.id,
68 Product.project == self,
69 Product.active == True,
70- ProductSet.getProductPrivacyFilter(user))
71+ privacy_filter)
72 result = store.find(columns, conditions)
73 result.group_by(Milestone.name)
74 if only_active:
75@@ -452,6 +453,7 @@
76 Product.project == self,
77 Milestone.product == Product.id,
78 Product.active == True,
79+ privacy_filter,
80 In(Milestone.name, milestone_names))
81 for product, name in (
82 store.find((Product, Milestone.name), product_conditions)):