Merge lp:~jcsackett/launchpad/filter-milestone-vocabulary-for-projectgroups into lp:launchpad

Proposed by j.c.sackett
Status: Merged
Approved by: j.c.sackett
Approved revision: no longer in the source branch.
Merged at revision: 16285
Proposed branch: lp:~jcsackett/launchpad/filter-milestone-vocabulary-for-projectgroups
Merge into: lp:launchpad
Diff against target: 83 lines (+35/-5)
2 files modified
lib/lp/registry/model/projectgroup.py (+6/-2)
lib/lp/registry/tests/test_milestone_vocabularies.py (+29/-3)
To merge this branch: bzr merge lp:~jcsackett/launchpad/filter-milestone-vocabulary-for-projectgroups
Reviewer Review Type Date Requested Status
Abel Deuring (community) code Approve
Review via email: mp+134667@code.launchpad.net

Commit message

Updates project group milestone filtering to not display milestones from associated private products if the user shouldn't see them.

Description of the change

Summary
=======
As it currently stands, when milestones are fetched for a projectgroup, the
milestones from all associated products are fetched, regardless of whether or
not they belong to a private product the current user cannot see.

Projectgroup must be updated to not show milestones the user can't see, using
our existing filtering clause.

Preimp
======
None.

Implementation
==============
The method `ProjectGroup`.`_getMilestoneCondition`, which creates the query to
fetch milestones, is updated to pull the current user from the launchbag and
create the privacy filtering clause from that. It then adds that clause to the
existing query.

Tests have also been updated for this case.

Tests
=====
bin/test -vvct TestMilestoneVocabulary

QA
==
Ensure the milestones listed for a project does not include anything from
associated private products.

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/tests/test_milestone_vocabularies.py

To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) wrote :

Looks good.

But I am wondering if we need to change the expression returned by ProductSet.getProductPrivacyFilter():

Users may have an artifact grant for a bug/branch/blueprint of a private product but not a policy grant for the product itself; I suspect that we should add a clause like APGF.artifact == None to address this case.

But this affects of course other callsites of getProductPrivacyFilter(), so we should probably talk about it in our standup call on Monday.

review: Approve (code)
Revision history for this message
j.c.sackett (jcsackett) wrote :

> Users may have an artifact grant for a bug/branch/blueprint of a private
> product but not a policy grant for the product itself; I suspect that we
> should add a clause like APGF.artifact == None to address this case.
>
> But this affects of course other callsites of getProductPrivacyFilter(), so we
> should probably talk about it in our standup call on Monday.

I agree, especially after dicsussion on IRC. Let's bring this up in the next standup.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/model/projectgroup.py'
2--- lib/lp/registry/model/projectgroup.py 2012-10-19 03:01:32 +0000
3+++ lib/lp/registry/model/projectgroup.py 2012-11-16 20:43:23 +0000
4@@ -407,8 +407,12 @@
5
6 def _getMilestoneCondition(self):
7 """See `HasMilestonesMixin`."""
8- return And(Milestone.productID == Product.id,
9- Product.projectID == self.id)
10+ user = getUtility(ILaunchBag).user
11+ privacy_filter = ProductSet.getProductPrivacyFilter(user)
12+ return And(
13+ Milestone.productID == Product.id,
14+ Product.projectID == self.id,
15+ privacy_filter)
16
17 def _getMilestones(self, user, only_active):
18 """Return a list of milestones for this project group.
19
20=== modified file 'lib/lp/registry/tests/test_milestone_vocabularies.py'
21--- lib/lp/registry/tests/test_milestone_vocabularies.py 2012-10-11 04:57:59 +0000
22+++ lib/lp/registry/tests/test_milestone_vocabularies.py 2012-11-16 20:43:23 +0000
23@@ -5,10 +5,9 @@
24
25 __metaclass__ = type
26
27-from unittest import TestCase
28-
29 from zope.component import getUtility
30
31+from lp.app.enums import InformationType
32 from lp.blueprints.interfaces.specification import ISpecificationSet
33 from lp.registry.interfaces.distribution import IDistributionSet
34 from lp.registry.interfaces.person import IPersonSet
35@@ -18,20 +17,47 @@
36 from lp.testing import (
37 login,
38 logout,
39+ person_logged_in,
40+ TestCaseWithFactory,
41 )
42 from lp.testing.layers import DatabaseFunctionalLayer
43
44
45-class TestMilestoneVocabulary(TestCase):
46+class TestMilestoneVocabulary(TestCaseWithFactory):
47 """Test that the MilestoneVocabulary behaves as expected."""
48+
49 layer = DatabaseFunctionalLayer
50
51 def setUp(self):
52+ super(TestMilestoneVocabulary, self).setUp()
53 login('test@canonical.com')
54
55 def tearDown(self):
56+ super(TestMilestoneVocabulary, self).tearDown()
57 logout()
58
59+ def test_project_group_does_not_show_nonpublic_products(self):
60+ # Milestones for a projectgroup should not include those on an
61+ # associated private product.
62+ owner = self.factory.makePerson()
63+ group = self.factory.makeProject(owner=owner)
64+ public = self.factory.makeProduct(project=group, owner=owner)
65+ private = self.factory.makeProduct(project=group, owner=owner,
66+ information_type=InformationType.PROPRIETARY)
67+ with person_logged_in(owner):
68+ m1 = self.factory.makeMilestone(name='public', product=public)
69+ m2 = self.factory.makeMilestone(name='private', product=private)
70+ vocabulary = MilestoneVocabulary(group)
71+ expected = [m1.title]
72+ listing = [term.title for term in vocabulary]
73+ self.assertEqual(expected, listing)
74+
75+ with person_logged_in(owner):
76+ vocabulary = MilestoneVocabulary(group)
77+ expected = [m1.title, m2.title]
78+ listing = [term.title for term in vocabulary]
79+ self.assertEqual(expected, listing)
80+
81 def testProductMilestoneVocabulary(self):
82 """Test of MilestoneVocabulary for a product."""
83 firefox = getUtility(IProductSet).getByName('firefox')