Merge lp:~abentley/launchpad/product-specifications-privacy into lp:launchpad

Proposed by Aaron Bentley on 2012-10-16
Status: Merged
Approved by: Aaron Bentley on 2012-10-17
Approved revision: no longer in the source branch.
Merged at revision: 16167
Proposed branch: lp:~abentley/launchpad/product-specifications-privacy
Merge into: lp:launchpad
Prerequisite: lp:~abentley/launchpad/product-specifications-storm
Diff against target: 150 lines (+79/-3)
4 files modified
lib/lp/blueprints/browser/tests/test_specificationtarget.py (+29/-1)
lib/lp/registry/browser/tests/test_product.py (+19/-1)
lib/lp/registry/model/product.py (+3/-1)
lib/lp/registry/tests/test_product.py (+28/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/product-specifications-privacy
Reviewer Review Type Date Requested Status
Deryck Hodge (community) 2012-10-16 Approve on 2012-10-17
Review via email: mp+130003@code.launchpad.net

Commit Message

Enable privacy for Product.specifications.

Description of the Change

= Summary =
Fix bug #1058411: private blueprints break product pages with specification listings

== Proposed fix ==
Update Product.specifications to repect privacy using get_specification_privacy_filter

== Pre-implementation notes ==
None

== LOC Rationale ==
Part of Private Projects.

== Implementation details ==
None

== Tests ==
bin/test -t TestPrivacy.test_product_specs -t TestProductView.test_index_proprietary_specification -t test_product.TestSpecifications

== Demo and Q/A ==
Add a proprietary specification to a project. It should be listed in the portlet and in +specs. Using the +sharing page, remove your ability to see proprietary information. It should be gone from the portlet and +specs, but you should be able to see everything else.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/testing/factory.py
  lib/lp/blueprints/model/specification.py
  lib/lp/registry/browser/tests/test_product.py
  lib/lp/blueprints/model/sprint.py
  lib/lp/registry/model/product.py
  lib/lp/registry/model/person.py
  lib/lp/registry/tests/test_person.py
  lib/lp/blueprints/browser/tests/test_specificationtarget.py
  lib/lp/registry/tests/test_product.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/blueprints/browser/tests/test_specificationtarget.py'
2--- lib/lp/blueprints/browser/tests/test_specificationtarget.py 2012-06-04 16:13:51 +0000
3+++ lib/lp/blueprints/browser/tests/test_specificationtarget.py 2012-10-17 14:52:22 +0000
4@@ -9,7 +9,10 @@
5 from zope.component import getUtility
6 from zope.security.proxy import removeSecurityProxy
7
8-from lp.app.enums import ServiceUsage
9+from lp.app.enums import (
10+ InformationType,
11+ ServiceUsage,
12+ )
13 from lp.blueprints.browser.specificationtarget import HasSpecificationsView
14 from lp.blueprints.interfaces.specification import ISpecificationSet
15 from lp.blueprints.interfaces.specificationtarget import (
16@@ -18,7 +21,9 @@
17 )
18 from lp.blueprints.publisher import BlueprintsLayer
19 from lp.testing import (
20+ BrowserTestCase,
21 login_person,
22+ person_logged_in,
23 TestCaseWithFactory,
24 )
25 from lp.testing.layers import DatabaseFunctionalLayer
26@@ -315,3 +320,26 @@
27 self.assertIn(picker_vocab, text)
28 focus_script = "setFocusByName('field.search_text')"
29 self.assertIn(focus_script, text)
30+
31+
32+class TestPrivacy(BrowserTestCase):
33+
34+ layer = DatabaseFunctionalLayer
35+
36+ def test_product_specs(self):
37+ # Proprietary specs are only listed for users who can see them.
38+ # Other users see the page, but not the private specs.
39+ proprietary = self.factory.makeSpecification(
40+ information_type=InformationType.PROPRIETARY)
41+ product = proprietary.product
42+ public = self.factory.makeSpecification(product=product)
43+ with person_logged_in(product.owner):
44+ product.blueprints_usage = ServiceUsage.LAUNCHPAD
45+ browser = self.getViewBrowser(product, '+specs')
46+ self.assertIn(public.name, browser.contents)
47+ self.assertNotIn(proprietary.name, browser.contents)
48+ with person_logged_in(None):
49+ browser = self.getViewBrowser(product, '+specs',
50+ user=product.owner)
51+ self.assertIn(public.name, browser.contents)
52+ self.assertIn(proprietary.name, browser.contents)
53
54=== modified file 'lib/lp/registry/browser/tests/test_product.py'
55--- lib/lp/registry/browser/tests/test_product.py 2012-10-16 00:57:45 +0000
56+++ lib/lp/registry/browser/tests/test_product.py 2012-10-17 14:52:22 +0000
57@@ -296,7 +296,7 @@
58 InformationType.PROPRIETARY, product.information_type)
59
60
61-class TestProductView(TestCaseWithFactory):
62+class TestProductView(BrowserTestCase):
63 """Tests the ProductView."""
64
65 layer = DatabaseFunctionalLayer
66@@ -431,6 +431,24 @@
67 team_membership_policy_data,
68 cache.objects['team_membership_policy_data'])
69
70+ def test_index_proprietary_specification(self):
71+ # Ordinary users can see page, but proprietary specs are only listed
72+ # for users with access to them.
73+ proprietary = self.factory.makeSpecification(
74+ information_type=InformationType.PROPRIETARY)
75+ product = proprietary.product
76+ with person_logged_in(product.owner):
77+ product.blueprints_usage = ServiceUsage.LAUNCHPAD
78+ public = self.factory.makeSpecification(product=product)
79+ browser = self.getViewBrowser(product, '+index')
80+ self.assertIn(public.name, browser.contents)
81+ self.assertNotIn(proprietary.name, browser.contents)
82+ with person_logged_in(None):
83+ browser = self.getViewBrowser(product, '+index',
84+ user=product.owner)
85+ self.assertIn(public.name, browser.contents)
86+ self.assertIn(proprietary.name, browser.contents)
87+
88
89 class TestProductEditView(BrowserTestCase):
90 """Tests for the ProductEditView"""
91
92=== modified file 'lib/lp/registry/model/product.py'
93--- lib/lp/registry/model/product.py 2012-10-17 14:52:22 +0000
94+++ lib/lp/registry/model/product.py 2012-10-17 14:52:22 +0000
95@@ -96,6 +96,7 @@
96 )
97 from lp.blueprints.model.specification import (
98 get_specification_filters,
99+ get_specification_privacy_filter,
100 HasSpecificationsMixin,
101 Specification,
102 SPECIFICATION_POLICY_ALLOWED_TYPES,
103@@ -1355,7 +1356,8 @@
104 # - completeness.
105 # - informational.
106 #
107- clauses = [Specification.product == self]
108+ clauses = [Specification.product == self,
109+ get_specification_privacy_filter(user)]
110 clauses.extend(get_specification_filters(filter))
111 if prejoin_people:
112 results = self._preload_specifications_people(clauses)
113
114=== modified file 'lib/lp/registry/tests/test_product.py'
115--- lib/lp/registry/tests/test_product.py 2012-10-17 14:52:22 +0000
116+++ lib/lp/registry/tests/test_product.py 2012-10-17 14:52:22 +0000
117@@ -1758,6 +1758,34 @@
118 result = list_result(product, ['def'])
119 self.assertEqual([blueprint2], result)
120
121+ def test_proprietary_not_listed(self):
122+ # Proprietary blueprints are not listed for random users
123+ blueprint1 = self.makeSpec(
124+ information_type=InformationType.PROPRIETARY)
125+ self.assertEqual([], list_result(blueprint1.product))
126+
127+ def test_proprietary_listed_for_artifact_grant(self):
128+ # Proprietary blueprints are listed for users with an artifact grant.
129+ blueprint1 = self.makeSpec(
130+ information_type=InformationType.PROPRIETARY)
131+ grant = self.factory.makeAccessArtifactGrant(
132+ concrete_artifact=blueprint1)
133+ self.assertEqual(
134+ [blueprint1],
135+ list_result(blueprint1.product, user=grant.grantee))
136+
137+ def test_proprietary_listed_for_policy_grant(self):
138+ # Proprietary blueprints are listed for users with a policy grant.
139+ blueprint1 = self.makeSpec(
140+ information_type=InformationType.PROPRIETARY)
141+ policy_source = getUtility(IAccessPolicySource)
142+ (policy,) = policy_source.find(
143+ [(blueprint1.product, InformationType.PROPRIETARY)])
144+ grant = self.factory.makeAccessPolicyGrant(policy)
145+ self.assertEqual(
146+ [blueprint1],
147+ list_result(blueprint1.product, user=grant.grantee))
148+
149
150 class TestWebService(WebServiceTestCase):
151