Merge lp:~abentley/launchpad/fix-banner into lp:launchpad

Proposed by Aaron Bentley on 2012-09-12
Status: Merged
Approved by: Aaron Bentley on 2012-09-12
Approved revision: no longer in the source branch.
Merged at revision: 15959
Proposed branch: lp:~abentley/launchpad/fix-banner
Merge into: lp:launchpad
Diff against target: 145 lines (+60/-2)
5 files modified
lib/lp/blueprints/browser/tests/test_specification.py (+22/-0)
lib/lp/blueprints/model/specification.py (+2/-1)
lib/lp/registry/interfaces/informationtype.py (+21/-0)
lib/lp/services/webapp/publisher.py (+12/-1)
lib/lp/testing/factory.py (+3/-0)
To merge this branch: bzr merge lp:~abentley/launchpad/fix-banner
Reviewer Review Type Date Requested Status
Deryck Hodge (community) 2012-09-12 Approve on 2012-09-12
Review via email: mp+124052@code.launchpad.net

Commit Message

Fix privacy banner for Specification.

Description of the Change

= Summary =
The privacy banner shows for Specification pages, but only +index describes information type.

== Proposed fix ==
Make all views that have Specification as their context work.

== Pre-implementation notes ==
None

== LOC Rationale ==
Part of private projects

== Implementation details ==
Provide a default implementation of LaunchpadView.information_type. It uses the new IInformationType interface to get the InformationType of a context object. Implement IInformationType on Specification.

== Tests ==
bin/test -t est_view_banner spec

== Demo and Q/A ==
Create a Proprietary blueprint. Go to every related page. Their banners should all say the page contains Proprietary information.

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/services/webapp/publisher.py
  lib/lp/registry/interfaces/informationtype.py
  lib/lp/blueprints/model/specification.py
  lib/lp/blueprints/browser/tests/test_specification.py

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

As mentioned on IRC, consider making the test more specific to ensure the phrase is actually in the banner and not somewhere else in browser.contents. Otherwise, this looks great. I particularly like the IInformationType approach to this.

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_specification.py'
2--- lib/lp/blueprints/browser/tests/test_specification.py 2012-09-13 14:16:11 +0000
3+++ lib/lp/blueprints/browser/tests/test_specification.py 2012-09-14 11:28:57 +0000
4@@ -5,6 +5,7 @@
5
6 from datetime import datetime
7 import json
8+import re
9 import unittest
10
11 from BeautifulSoup import BeautifulSoup
12@@ -269,6 +270,27 @@
13 self.set_secrecy(spec, person)
14 self.assertEqual(InformationType.PUBLIC, spec.information_type)
15
16+ def test_view_banner(self):
17+ """The privacy banner should reflect the information_type."""
18+ owner = self.factory.makePerson()
19+ spec = self.factory.makeSpecification(
20+ information_type=InformationType.PROPRIETARY, owner=owner)
21+
22+ privacy_banner = soupmatchers.Tag('privacy-banner', True,
23+ attrs={'class': 'banner-text'},
24+ text=re.compile('This page contains Proprietary information'))
25+
26+ getUtility(IService, 'sharing').ensureAccessGrants(
27+ [owner], owner, specifications=[spec],
28+ ignore_permissions=True)
29+
30+ browser = self.getViewBrowser(spec, '+index', user=owner)
31+ self.assertThat(browser.contents,
32+ soupmatchers.HTMLContains(privacy_banner))
33+ browser = self.getViewBrowser(spec, '+subscribe', user=owner)
34+ self.assertThat(browser.contents,
35+ soupmatchers.HTMLContains(privacy_banner))
36+
37
38 # canonical_url erroneously returns http://blueprints.launchpad.dev/+new
39 NEW_SPEC_FROM_ROOT_URL = 'http://blueprints.launchpad.dev/specs/+new'
40
41=== modified file 'lib/lp/blueprints/model/specification.py'
42--- lib/lp/blueprints/model/specification.py 2012-09-13 14:16:11 +0000
43+++ lib/lp/blueprints/model/specification.py 2012-09-14 11:28:57 +0000
44@@ -81,6 +81,7 @@
45 from lp.registry.errors import CannotChangeInformationType
46 from lp.registry.interfaces.distribution import IDistribution
47 from lp.registry.interfaces.distroseries import IDistroSeries
48+from lp.registry.interfaces.informationtype import IInformationType
49 from lp.registry.interfaces.person import validate_public_person
50 from lp.registry.interfaces.product import IProduct
51 from lp.registry.interfaces.productseries import IProductSeries
52@@ -130,7 +131,7 @@
53 class Specification(SQLBase, BugLinkTargetMixin):
54 """See ISpecification."""
55
56- implements(ISpecification, IBugLinkTarget)
57+ implements(ISpecification, IBugLinkTarget, IInformationType)
58
59 _defaultOrder = ['-priority', 'definition_status', 'name', 'id']
60
61
62=== added file 'lib/lp/registry/interfaces/informationtype.py'
63--- lib/lp/registry/interfaces/informationtype.py 1970-01-01 00:00:00 +0000
64+++ lib/lp/registry/interfaces/informationtype.py 2012-09-14 11:28:57 +0000
65@@ -0,0 +1,21 @@
66+# Copyright 2012 Canonical Ltd. This software is licensed under the
67+# GNU Affero General Public License version 3 (see the file LICENSE).
68+
69+__metaclass__ = type
70+__all__ = [
71+ 'IInformationType',
72+ ]
73+
74+from zope.schema import Choice
75+
76+from lp import _
77+from lp.app.interfaces.launchpad import IPrivacy
78+from lp.registry.enums import InformationType
79+
80+
81+class IInformationType(IPrivacy):
82+
83+ information_type = Choice(
84+ title=_('Information Type'),
85+ vocabulary=InformationType,
86+ )
87
88=== modified file 'lib/lp/services/webapp/publisher.py'
89--- lib/lp/services/webapp/publisher.py 2012-09-11 02:01:52 +0000
90+++ lib/lp/services/webapp/publisher.py 2012-09-14 11:28:57 +0000
91@@ -90,6 +90,7 @@
92 )
93 from lp.services.webapp.url import urlappend
94 from lp.services.webapp.vhosts import allvhosts
95+from lp.registry.interfaces.informationtype import IInformationType
96
97 # Monkeypatch NotFound to always avoid generating OOPS
98 # from NotFound in web service calls.
99@@ -301,6 +302,14 @@
100 else:
101 return False
102
103+ @property
104+ def information_type(self):
105+ """A view has the information_type of its context."""
106+ information_typed = IInformationType(self.context, None)
107+ if information_typed is None:
108+ return None
109+ return information_typed.information_type.title
110+
111 def __init__(self, context, request):
112 self.context = context
113 self.request = request
114@@ -959,7 +968,9 @@
115 nextobj = None
116 else:
117 # Circular import; breaks make.
118- from lp.services.webapp.breadcrumb import Breadcrumb
119+ from lp.services.webapp.breadcrumb import (
120+ Breadcrumb,
121+ )
122 stepthrough_page = queryMultiAdapter(
123 (self.context, self.request), name=name)
124 if stepthrough_page:
125
126=== modified file 'lib/lp/testing/factory.py'
127--- lib/lp/testing/factory.py 2012-09-12 12:17:27 +0000
128+++ lib/lp/testing/factory.py 2012-09-14 11:28:57 +0000
129@@ -142,6 +142,7 @@
130 DistroSeriesDifferenceStatus,
131 DistroSeriesDifferenceType,
132 InformationType,
133+ PUBLIC_INFORMATION_TYPES,
134 TeamMembershipPolicy,
135 )
136 from lp.registry.interfaces.accesspolicy import (
137@@ -2110,6 +2111,8 @@
138 priority=priority)
139 naked_spec = removeSecurityProxy(spec)
140 if information_type is not None:
141+ if information_type not in PUBLIC_INFORMATION_TYPES:
142+ naked_spec.target._ensurePolicies([information_type])
143 naked_spec.transitionToInformationType(
144 information_type, spec.target.owner)
145 if status.name not in status_names: