launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #04399
[Merge] lp:~abentley/launchpad/json-serialization into lp:launchpad
Aaron Bentley has proposed merging lp:~abentley/launchpad/json-serialization into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~abentley/launchpad/json-serialization/+merge/69519
= Summary =
Make the IJSONRequestCache serialization reusable.
== Proposed fix ==
Use the view, rather than the template, to serialize the IJSONRequestCache
== Pre-implementation notes ==
Discussed with Ian Booth, J.C. Sackett and Brad Crittenden.
== Implementation details ==
The main change is the getCacheJSON method, which implements the serialization
logic. There are two changes:
1. The text format of the cache generation has changed to generate the cache in
a single assignment. Previously, each value was assigned in a separate
<script> tag.
2. Email obfuscation is now performed at a low level in the marshaller, rather
than explicitly in the template.
Aside from that, the new cache is equivalent to the old one.
Many tests failed because the template now requires the view to provide
getCacheJSON. In most cases, this could be fixed by making the view a subclass
of LaunchpadView. That change made some constructors redundant, so they were
removed. In some cases, no specific view class had been specified, and so
specifying LaunchpadView was enough.
Some tests relied on the specific text formatting, so they were adjusted to use
the new formatting, or to make assertions about the serialized values.
Some tests broke because email obfuscation wasn't being triggered. It had
relied on the fact that when a user is logged it, the request's principal does
not provide IUnauthenticatedPrincipal. However, in tests, the request
principal is typically None, which also doesn't provide
IUnauthenticatedPrincipal. We usually use ILaunchbag.user to determine the
current user, so changing the marshaller to use this fixed the tests.
I also fixed some lint.
== Tests ==
bin/test -t test_marshallers -t test_publisher
== Demo and Q/A ==
Create a source package with an email address in a text field.
As a logged-in user, visit its +sharing-details page and look at the page
source. You should see LP.cache having multiple values assigned at once.
After logging out, only the context should be assigned, and the email address
should be obfuscated.
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/soyuz/browser/distroseriessourcepackagerelease.py
lib/lp/registry/browser/sourcepackage.py
lib/lp/registry/browser/peoplemerge.py
lib/canonical/launchpad/webapp/publisher.py
lib/lp/code/browser/bazaar.py
lib/lp/registry/browser/codeofconduct.py
lib/lp/soyuz/browser/sourcepackage.py
lib/lp/registry/browser/distributionsourcepackage.py
lib/canonical/launchpad/webapp/tests/test_publisher.py
lib/lp/soyuz/browser/distroseriesbinarypackage.py
lib/lp/app/templates/base-layout-macros.pt
lib/lp/testing/__init__.py
lib/lp/bugs/browser/configure.zcml
lib/lp/bugs/browser/cve.py
lib/lp/soyuz/browser/distroarchseriesbinarypackagerelease.py
lib/lp/soyuz/browser/distroarchseriesbinarypackage.py
lib/lp/translations/browser/tests/test_sharing_details.py
lib/lp/translations/browser/translationgroup.py
lib/lp/app/webservice/tests/test_marshallers.py
lib/lp/blueprints/browser/configure.zcml
lib/lp/registry/browser/teammembership.py
lib/lp/app/webservice/marshallers.py
lib/lp/translations/browser/translations.py
lib/lp/translations/browser/sourcepackage.py
lib/lp/registry/browser/tests/test_subscription_links.py
./lib/lp/translations/browser/tests/test_sharing_details.py
218: E251 no spaces around keyword / parameter equals
226: E251 no spaces around keyword / parameter equals
279: E251 no spaces around keyword / parameter equals
311: E251 no spaces around keyword / parameter equals
--
https://code.launchpad.net/~abentley/launchpad/json-serialization/+merge/69519
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~abentley/launchpad/json-serialization into lp:launchpad.
=== modified file 'lib/canonical/launchpad/webapp/publisher.py'
--- lib/canonical/launchpad/webapp/publisher.py 2011-07-21 22:45:05 +0000
+++ lib/canonical/launchpad/webapp/publisher.py 2011-07-27 18:06:47 +0000
@@ -26,6 +26,7 @@
]
import httplib
+import simplejson
from zope.app import zapi
from zope.app.publisher.interfaces.xmlrpc import IXMLRPCView
@@ -51,7 +52,14 @@
)
from zope.traversing.browser.interfaces import IAbsoluteURL
+from lazr.restful import (
+ EntryResource,
+ ResourceJSONEncoder,
+ )
from lazr.restful.declarations import error_status
+from lazr.restful.interfaces import IJSONRequestCache
+
+from lazr.restful.tales import WebLayerAPI
from canonical.launchpad.layers import (
LaunchpadLayer,
@@ -340,6 +348,17 @@
info_message = property(_getInfoMessage, _setInfoMessage)
+ def getCacheJSON(self):
+ if self.user is not None:
+ cache = dict(IJSONRequestCache(self.request).objects)
+ else:
+ cache = dict()
+ if WebLayerAPI(self.context).is_entry:
+ cache['context'] = self.context
+ return simplejson.dumps(
+ cache, cls=ResourceJSONEncoder,
+ media_type=EntryResource.JSON_TYPE)
+
class LaunchpadXMLRPCView(UserAttributeCache):
"""Base class for writing XMLRPC view code."""
=== modified file 'lib/canonical/launchpad/webapp/tests/test_publisher.py'
--- lib/canonical/launchpad/webapp/tests/test_publisher.py 2010-10-12 01:11:41 +0000
+++ lib/canonical/launchpad/webapp/tests/test_publisher.py 2011-07-27 18:06:47 +0000
@@ -5,10 +5,96 @@
DocTestSuite,
ELLIPSIS,
)
+from unittest import TestLoader, TestSuite
+
+from lazr.restful.interfaces import IJSONRequestCache
+import simplejson
+from zope.component import getUtility
+
+from canonical.testing.layers import DatabaseFunctionalLayer
+from canonical.launchpad.webapp.publisher import LaunchpadView
+from canonical.launchpad.webapp.servers import LaunchpadTestRequest
+from lp.services.worlddata.interfaces.country import ICountrySet
+from lp.testing import (
+ logout,
+ person_logged_in,
+ TestCaseWithFactory,
+ )
from canonical.launchpad.webapp import publisher
+class TestLaunchpadView(TestCaseWithFactory):
+
+ layer = DatabaseFunctionalLayer
+
+ def test_getCacheJSON_non_resource_context(self):
+ view = LaunchpadView(object(), LaunchpadTestRequest())
+ self.assertEqual('{}', view.getCacheJSON())
+
+ @staticmethod
+ def getCanada():
+ return getUtility(ICountrySet)['CA']
+
+ def assertIsCanada(self, json_dict):
+ self.assertIs(None, json_dict['description'])
+ self.assertEqual('CA', json_dict['iso3166code2'])
+ self.assertEqual('CAN', json_dict['iso3166code3'])
+ self.assertEqual('Canada', json_dict['name'])
+ self.assertIs(None, json_dict['title'])
+ self.assertContentEqual(
+ ['description', 'http_etag', 'iso3166code2', 'iso3166code3',
+ 'name', 'resource_type_link', 'self_link', 'title'],
+ json_dict.keys())
+
+ def test_getCacheJSON_resource_context(self):
+ view = LaunchpadView(self.getCanada(), LaunchpadTestRequest())
+ json_dict = simplejson.loads(view.getCacheJSON())['context']
+ self.assertIsCanada(json_dict)
+
+ def test_getCacheJSON_non_resource_object(self):
+ request = LaunchpadTestRequest()
+ view = LaunchpadView(object(), request)
+ IJSONRequestCache(request).objects['my_bool'] = True
+ with person_logged_in(self.factory.makePerson()):
+ self.assertEqual('{"my_bool": true}', view.getCacheJSON())
+
+ def test_getCacheJSON_resource_object(self):
+ request = LaunchpadTestRequest()
+ view = LaunchpadView(object(), request)
+ IJSONRequestCache(request).objects['country'] = self.getCanada()
+ with person_logged_in(self.factory.makePerson()):
+ json_dict = simplejson.loads(view.getCacheJSON())['country']
+ self.assertIsCanada(json_dict)
+
+ def test_getCacheJSON_context_overrides_objects(self):
+ request = LaunchpadTestRequest()
+ view = LaunchpadView(self.getCanada(), request)
+ IJSONRequestCache(request).objects['context'] = True
+ with person_logged_in(self.factory.makePerson()):
+ json_dict = simplejson.loads(view.getCacheJSON())['context']
+ self.assertIsCanada(json_dict)
+
+ def test_getCache_anonymous(self):
+ request = LaunchpadTestRequest()
+ view = LaunchpadView(self.getCanada(), request)
+ self.assertIs(None, view.user)
+ IJSONRequestCache(request).objects['my_bool'] = True
+ json_dict = simplejson.loads(view.getCacheJSON())
+ self.assertIsCanada(json_dict['context'])
+ self.assertFalse('my_bool' in json_dict)
+
+ def test_getCache_anonymous_obfuscated(self):
+ request = LaunchpadTestRequest()
+ branch = self.factory.makeBranch(name='user@domain')
+ logout()
+ view = LaunchpadView(branch, request)
+ self.assertIs(None, view.user)
+ self.assertNotIn('user@domain', view.getCacheJSON())
+
+
def test_suite():
- suite = DocTestSuite(publisher, optionflags=ELLIPSIS)
+ suite = TestSuite()
+ suite.addTest(DocTestSuite(publisher, optionflags=ELLIPSIS))
+ suite.addTest(TestLoader().loadTestsFromName(__name__))
return suite
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2011-07-08 11:46:41 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2011-07-27 18:06:47 +0000
@@ -168,15 +168,9 @@
tal:content="string:LP.links['${key}'] =
'${links/?key/fmt:api_url}';">
</script>
- <script tal:repeat="key objects"
- tal:content="string:LP.cache['${key}'] =
- ${objects/?key/webservice:json};">
- </script>
</tal:cache>
- <script tal:condition="context/webservice:is_entry"
- tal:content="string:LP.cache['context'] =
- ${context/webservice:json/fmt:obfuscate-email};">
+ <script tal:content="string:LP.cache = ${view/getCacheJSON};">
</script>
</metal:lp-client-cache>
=== modified file 'lib/lp/app/webservice/marshallers.py'
--- lib/lp/app/webservice/marshallers.py 2011-07-12 10:02:51 +0000
+++ lib/lp/app/webservice/marshallers.py 2011-07-27 18:06:47 +0000
@@ -13,9 +13,10 @@
from lazr.restful.marshallers import (
TextFieldMarshaller as LazrTextFieldMarshaller,
)
-from zope.app.security.interfaces import IUnauthenticatedPrincipal
+from zope.component import getUtility
from lp.services.utils import obfuscate_email
+from canonical.launchpad.webapp.interfaces import ILaunchBag
class TextFieldMarshaller(LazrTextFieldMarshaller):
@@ -26,7 +27,7 @@
Return the value as is.
"""
- if (value is not None and
- IUnauthenticatedPrincipal.providedBy(self.request.principal)):
+
+ if (value is not None and getUtility(ILaunchBag).user is None):
return obfuscate_email(value)
return value
=== modified file 'lib/lp/app/webservice/tests/test_marshallers.py'
--- lib/lp/app/webservice/tests/test_marshallers.py 2011-07-12 10:02:51 +0000
+++ lib/lp/app/webservice/tests/test_marshallers.py 2011-07-27 18:06:47 +0000
@@ -6,17 +6,19 @@
__metaclass__ = type
import transaction
-from zope.component import getUtility
from canonical.launchpad.testing.pages import (
LaunchpadWebServiceCaller,
webservice_for_person,
)
-from canonical.launchpad.webapp.interfaces import IPlacelessAuthUtility
from canonical.launchpad.webapp.servers import WebServiceTestRequest
from canonical.testing.layers import DatabaseFunctionalLayer
from lp.app.webservice.marshallers import TextFieldMarshaller
-from lp.testing import logout, TestCaseWithFactory
+from lp.testing import (
+ logout,
+ person_logged_in,
+ TestCaseWithFactory,
+ )
def ws_url(bug):
@@ -28,28 +30,17 @@
layer = DatabaseFunctionalLayer
- def _makeRequest(self, is_anonymous):
- """Create either an anonymous or authenticated request."""
- request = WebServiceTestRequest()
- if is_anonymous:
- request.setPrincipal(
- getUtility(IPlacelessAuthUtility).unauthenticatedPrincipal())
- else:
- request.setPrincipal(self.factory.makePerson())
- return request
-
def test_unmarshall_obfuscated(self):
- # Data is obfuccated if the request is anonynous.
- request = self._makeRequest(is_anonymous=True)
- marshaller = TextFieldMarshaller(None, request)
+ # Data is obfuscated if the user is anonynous.
+ marshaller = TextFieldMarshaller(None, WebServiceTestRequest())
result = marshaller.unmarshall(None, u"foo@xxxxxxxxxxx")
self.assertEqual(u"<email address hidden>", result)
def test_unmarshall_not_obfuscated(self):
- # Data is not obfuccated if the request is authenticated.
- request = self._makeRequest(is_anonymous=False)
- marshaller = TextFieldMarshaller(None, request)
- result = marshaller.unmarshall(None, u"foo@xxxxxxxxxxx")
+ # Data is not obfuccated if the user is authenticated.
+ marshaller = TextFieldMarshaller(None, WebServiceTestRequest())
+ with person_logged_in(self.factory.makePerson()):
+ result = marshaller.unmarshall(None, u"foo@xxxxxxxxxxx")
self.assertEqual(u"foo@xxxxxxxxxxx", result)
=== modified file 'lib/lp/blueprints/browser/configure.zcml'
--- lib/lp/blueprints/browser/configure.zcml 2011-06-19 13:32:15 +0000
+++ lib/lp/blueprints/browser/configure.zcml 2011-07-27 18:06:47 +0000
@@ -135,6 +135,7 @@
permission="zope.Public"/>
<browser:pages
for="lp.blueprints.interfaces.sprint.IHasSprints"
+ class="canonical.launchpad.webapp.LaunchpadView"
facet="overview"
permission="zope.Public">
<browser:page
=== modified file 'lib/lp/bugs/browser/configure.zcml'
--- lib/lp/bugs/browser/configure.zcml 2011-07-21 05:13:08 +0000
+++ lib/lp/bugs/browser/configure.zcml 2011-07-27 18:06:47 +0000
@@ -852,6 +852,7 @@
name="+index"/>
<browser:pages
for="lp.bugs.interfaces.bugtracker.IRemoteBug"
+ class="canonical.launchpad.webapp.LaunchpadView"
permission="zope.Public">
<browser:page
name="+index"
=== modified file 'lib/lp/bugs/browser/cve.py'
--- lib/lp/bugs/browser/cve.py 2011-02-24 15:30:54 +0000
+++ lib/lp/bugs/browser/cve.py 2011-07-27 18:06:47 +0000
@@ -20,6 +20,7 @@
canonical_url,
ContextMenu,
GetitemNavigation,
+ LaunchpadView,
Link,
)
from canonical.launchpad.webapp.batching import BatchNavigator
@@ -122,11 +123,10 @@
heading = 'Remove links to bug reports'
-class CveSetView:
+class CveSetView(LaunchpadView):
def __init__(self, context, request):
- self.context = context
- self.request = request
+ super(CveSetView, self).__init__(context, request)
self.notices = []
self.results = None
self.text = self.request.form.get('text', None)
=== modified file 'lib/lp/code/browser/bazaar.py'
--- lib/lp/code/browser/bazaar.py 2010-08-31 11:24:54 +0000
+++ lib/lp/code/browser/bazaar.py 2011-07-27 18:06:47 +0000
@@ -87,7 +87,7 @@
@cachedproperty
def short_product_tag_cloud(self):
"""Show a preview of the product tag cloud."""
- return BazaarProductView().products(
+ return BazaarProductView(None, None).products(
num_products=config.launchpad.code_homepage_product_cloud_size)
@@ -150,7 +150,7 @@
self.request.response.redirect(redirect_url, status=301)
-class BazaarProductView:
+class BazaarProductView(LaunchpadView):
"""Browser class for products gettable with Bazaar."""
def _make_distribution_map(self, values, percentile_map):
=== modified file 'lib/lp/registry/browser/codeofconduct.py'
--- lib/lp/registry/browser/codeofconduct.py 2010-11-23 23:22:27 +0000
+++ lib/lp/registry/browser/codeofconduct.py 2011-07-27 18:06:47 +0000
@@ -220,7 +220,7 @@
self.request = request
-class SignedCodeOfConductAdminView:
+class SignedCodeOfConductAdminView(LaunchpadView):
"""Admin Console for SignedCodeOfConduct Entries."""
def __init__(self, context, request):
=== modified file 'lib/lp/registry/browser/distributionsourcepackage.py'
--- lib/lp/registry/browser/distributionsourcepackage.py 2011-06-29 16:23:36 +0000
+++ lib/lp/registry/browser/distributionsourcepackage.py 2011-07-27 18:06:47 +0000
@@ -130,7 +130,8 @@
def overview(self):
text = 'Overview'
- summary = 'General information about {0}'.format(self.context.displayname)
+ summary = 'General information about {0}'.format(
+ self.context.displayname)
return Link('', text, summary)
def bugs(self):
@@ -277,7 +278,7 @@
return Link('+changelog', text, icon="info")
-class DistributionSourcePackageBaseView:
+class DistributionSourcePackageBaseView(LaunchpadView):
"""Common features to all `DistributionSourcePackage` views."""
def releases(self):
@@ -633,7 +634,7 @@
cancel_url = next_url
-class DistributionSourcePackageHelpView:
+class DistributionSourcePackageHelpView(LaunchpadView):
"""A View to show Answers help."""
page_title = 'Help and support options'
=== modified file 'lib/lp/registry/browser/peoplemerge.py'
--- lib/lp/registry/browser/peoplemerge.py 2011-05-27 21:12:25 +0000
+++ lib/lp/registry/browser/peoplemerge.py 2011-07-27 18:06:47 +0000
@@ -139,7 +139,7 @@
naked_email.personID = self.target_person.id
naked_email.accountID = self.target_person.accountID
naked_email.status = EmailAddressStatus.NEW
- job = getUtility(IPersonSet).mergeAsync(
+ getUtility(IPersonSet).mergeAsync(
self.dupe_person, self.target_person, reviewer=self.user)
self.request.response.addInfoNotification(self.merge_message)
self.next_url = self.success_url
@@ -214,7 +214,6 @@
super(AdminTeamMergeView, self).validate(data)
dupe_team = data['dupe_person']
- target_team = data['target_person']
# We cannot merge the teams if there is a mailing list on the
# duplicate person, unless that mailing list is purged.
if self.hasMailingList(dupe_team):
@@ -342,19 +341,18 @@
return ''
-class RequestPeopleMergeMultipleEmailsView:
+class RequestPeopleMergeMultipleEmailsView(LaunchpadView):
"""Merge request view when dupe account has multiple email addresses."""
label = 'Merge Launchpad accounts'
page_title = label
def __init__(self, context, request):
- self.context = context
- self.request = request
+ super(RequestPeopleMergeMultipleEmailsView, self).__init__(
+ context, request)
self.form_processed = False
self.dupe = None
self.notified_addresses = []
- self.user = getUtility(ILaunchBag).user
def processForm(self):
dupe = self.request.form.get('dupe')
=== modified file 'lib/lp/registry/browser/sourcepackage.py'
--- lib/lp/registry/browser/sourcepackage.py 2011-06-29 16:23:36 +0000
+++ lib/lp/registry/browser/sourcepackage.py 2011-07-27 18:06:47 +0000
@@ -212,7 +212,8 @@
def overview(self):
text = 'Overview'
- summary = 'General information about {0}'.format(self.context.displayname)
+ summary = 'General information about {0}'.format(
+ self.context.displayname)
return Link('', text, summary)
def bugs(self):
@@ -227,7 +228,8 @@
def translations(self):
text = 'Translations'
- summary = 'Translations of {0} in Launchpad'.format(self.context.displayname)
+ summary = 'Translations of {0} in Launchpad'.format(
+ self.context.displayname)
return Link('', text, summary)
@@ -444,7 +446,7 @@
'The packaging link has already been deleted.')
-class SourcePackageView:
+class SourcePackageView(LaunchpadView):
"""A view for (distro series) source packages."""
def initialize(self):
=== modified file 'lib/lp/registry/browser/teammembership.py'
--- lib/lp/registry/browser/teammembership.py 2011-05-27 21:12:25 +0000
+++ lib/lp/registry/browser/teammembership.py 2011-07-27 18:06:47 +0000
@@ -25,7 +25,6 @@
LaunchpadView,
)
from canonical.launchpad.webapp.breadcrumb import Breadcrumb
-from canonical.launchpad.webapp.interfaces import ILaunchBag
from lp.app.errors import UnexpectedFormData
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.app.widgets.date import DateWidget
@@ -40,12 +39,10 @@
return "%s's membership" % self.context.person.displayname
-class TeamMembershipEditView:
+class TeamMembershipEditView(LaunchpadView):
def __init__(self, context, request):
- self.context = context
- self.request = request
- self.user = getUtility(ILaunchBag).user
+ super(TeamMembershipEditView, self).__init__(context, request)
self.errormessage = ""
self.prefix = 'membership'
self.max_year = 2050
@@ -256,7 +253,7 @@
assert self.context.status == TeamMembershipStatus.PROPOSED
- action = self.request.form.get('editproposed')
+ self.request.form.get('editproposed')
if self.request.form.get('decline'):
status = TeamMembershipStatus.DECLINED
elif self.request.form.get('approve'):
=== modified file 'lib/lp/registry/browser/tests/test_subscription_links.py'
--- lib/lp/registry/browser/tests/test_subscription_links.py 2011-06-22 14:09:43 +0000
+++ lib/lp/registry/browser/tests/test_subscription_links.py 2011-07-27 18:06:47 +0000
@@ -69,7 +69,7 @@
None, self.new_edit_link,
"Expected edit_bug_mail link missing")
# Ensure the LP.cache has been populated.
- self.assertTrue("LP.cache['administratedTeams']" in self.contents)
+ self.assertIn('LP.cache = {"administratedTeams": [', self.contents)
# Ensure the call to setup the subscription is in the HTML.
# Only check for the presence of setup's configuration step; more
# detailed checking is needlessly brittle.
=== modified file 'lib/lp/soyuz/browser/distroarchseriesbinarypackage.py'
--- lib/lp/soyuz/browser/distroarchseriesbinarypackage.py 2010-08-20 20:31:18 +0000
+++ lib/lp/soyuz/browser/distroarchseriesbinarypackage.py 2011-07-27 18:06:47 +0000
@@ -11,8 +11,8 @@
from canonical.launchpad.webapp import (
ApplicationMenu,
GetitemNavigation,
+ LaunchpadView,
)
-from canonical.launchpad.webapp.breadcrumb import Breadcrumb
from canonical.lazr.utils import smartquote
from lp.soyuz.interfaces.distroarchseriesbinarypackage import (
IDistroArchSeriesBinaryPackage,
@@ -31,11 +31,7 @@
usedfor = IDistroArchSeriesBinaryPackage
-class DistroArchSeriesBinaryPackageView:
-
- def __init__(self, context, request):
- self.context = context
- self.request = request
+class DistroArchSeriesBinaryPackageView(LaunchpadView):
@property
def page_title(self):
=== modified file 'lib/lp/soyuz/browser/distroarchseriesbinarypackagerelease.py'
--- lib/lp/soyuz/browser/distroarchseriesbinarypackagerelease.py 2010-08-20 20:31:18 +0000
+++ lib/lp/soyuz/browser/distroarchseriesbinarypackagerelease.py 2011-07-27 18:06:47 +0000
@@ -11,6 +11,7 @@
from canonical.launchpad.webapp import (
ApplicationMenu,
+ LaunchpadView,
Navigation,
)
from canonical.launchpad.webapp.breadcrumb import Breadcrumb
@@ -38,9 +39,8 @@
usedfor = IDistroArchSeriesBinaryPackageRelease
-class DistroArchSeriesBinaryPackageReleaseView:
+class DistroArchSeriesBinaryPackageReleaseView(LaunchpadView):
def __init__(self, context, request):
self.context = context
self.request = request
-
=== modified file 'lib/lp/soyuz/browser/distroseriesbinarypackage.py'
--- lib/lp/soyuz/browser/distroseriesbinarypackage.py 2010-08-20 20:31:18 +0000
+++ lib/lp/soyuz/browser/distroseriesbinarypackage.py 2011-07-27 18:06:47 +0000
@@ -12,6 +12,7 @@
from canonical.launchpad.webapp import (
ApplicationMenu,
+ LaunchpadView,
Navigation,
StandardLaunchpadFacets,
)
@@ -49,7 +50,7 @@
return self.context.binarypackagename.name
-class DistroSeriesBinaryPackageView:
+class DistroSeriesBinaryPackageView(LaunchpadView):
def __init__(self, context, request):
self.context = context
=== modified file 'lib/lp/soyuz/browser/distroseriessourcepackagerelease.py'
--- lib/lp/soyuz/browser/distroseriessourcepackagerelease.py 2010-08-20 20:31:18 +0000
+++ lib/lp/soyuz/browser/distroseriessourcepackagerelease.py 2011-07-27 18:06:47 +0000
@@ -10,6 +10,7 @@
from canonical.launchpad.webapp import (
ApplicationMenu,
+ LaunchpadView,
Navigation,
stepthrough,
)
@@ -49,7 +50,7 @@
return None
-class DistroSeriesSourcePackageReleaseView:
+class DistroSeriesSourcePackageReleaseView(LaunchpadView):
def __init__(self, context, request):
self.context = context
=== modified file 'lib/lp/soyuz/browser/sourcepackage.py'
--- lib/lp/soyuz/browser/sourcepackage.py 2011-05-12 12:09:17 +0000
+++ lib/lp/soyuz/browser/sourcepackage.py 2011-07-27 18:06:47 +0000
@@ -12,7 +12,10 @@
from zope.component import getUtility
-from canonical.launchpad.webapp import Navigation
+from canonical.launchpad.webapp import (
+ LaunchpadView,
+ Navigation,
+ )
from canonical.lazr.utils import smartquote
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.interfaces.distroseries import IDistroSeriesSet
@@ -21,7 +24,7 @@
)
-class SourcePackageChangelogView:
+class SourcePackageChangelogView(LaunchpadView):
"""View class for source package change logs."""
page_title = "Change log"
@@ -32,7 +35,7 @@
return smartquote("Change logs for " + self.context.title)
-class SourcePackageCopyrightView:
+class SourcePackageCopyrightView(LaunchpadView):
"""A view to display a source package's copyright information."""
page_title = "Copyright"
=== modified file 'lib/lp/testing/__init__.py'
--- lib/lp/testing/__init__.py 2011-07-21 18:38:50 +0000
+++ lib/lp/testing/__init__.py 2011-07-27 18:06:47 +0000
@@ -15,6 +15,7 @@
'build_yui_unittest_suite',
'celebrity_logged_in',
'ExpectedException',
+ 'extract_lp_cache',
'FakeTime',
'get_lsb_information',
'is_logged_in',
@@ -1306,3 +1307,8 @@
self.caught_exc = exc_value
return super(ExpectedException, self).__exit__(
exc_type, exc_value, traceback)
+
+
+def extract_lp_cache(text):
+ match = re.search(r'<script>LP.cache = (\{.*\});</script>', text)
+ return simplejson.loads(match.group(1))
=== modified file 'lib/lp/translations/browser/sourcepackage.py'
--- lib/lp/translations/browser/sourcepackage.py 2011-04-21 19:56:36 +0000
+++ lib/lp/translations/browser/sourcepackage.py 2011-07-27 18:06:47 +0000
@@ -43,7 +43,7 @@
from lp.translations.model.translationpackagingjob import TranslationMergeJob
-class SourcePackageTranslationsView(TranslationsMixin,
+class SourcePackageTranslationsView(LaunchpadView, TranslationsMixin,
TranslationSharingDetailsMixin):
@property
=== modified file 'lib/lp/translations/browser/tests/test_sharing_details.py'
--- lib/lp/translations/browser/tests/test_sharing_details.py 2011-06-30 16:49:37 +0000
+++ lib/lp/translations/browser/tests/test_sharing_details.py 2011-07-27 18:06:47 +0000
@@ -26,6 +26,7 @@
from lp.testing import (
BrowserTestCase,
EventRecorder,
+ extract_lp_cache,
person_logged_in,
TestCaseWithFactory,
)
@@ -938,10 +939,12 @@
sourcepackage = self.makeFullyConfiguredSharing()[0]
anon_browser = self._getSharingDetailsViewBrowser(sourcepackage)
# Anonymous users don't get cached objects due to bug #740208
- self.assertNotIn("LP.cache['productseries'] =", anon_browser.contents)
+ self.assertNotIn(
+ 'productseries', extract_lp_cache(anon_browser.contents))
browser = self._getSharingDetailsViewBrowser(
sourcepackage, user=self.user)
- self.assertIn("LP.cache['productseries'] =", browser.contents)
+ self.assertIn(
+ 'productseries', extract_lp_cache(browser.contents))
def test_potlist_only_ubuntu(self):
# Without a packaging link, only Ubuntu templates are listed.
=== modified file 'lib/lp/translations/browser/translationgroup.py'
--- lib/lp/translations/browser/translationgroup.py 2010-11-23 23:22:27 +0000
+++ lib/lp/translations/browser/translationgroup.py 2011-07-27 18:06:47 +0000
@@ -57,7 +57,7 @@
text = u"Translation groups"
-class TranslationGroupSetView:
+class TranslationGroupSetView(LaunchpadView):
"""Translation groups overview."""
page_title = "Translation groups"
label = page_title
=== modified file 'lib/lp/translations/browser/translations.py'
--- lib/lp/translations/browser/translations.py 2011-05-27 19:53:20 +0000
+++ lib/lp/translations/browser/translations.py 2011-07-27 18:06:47 +0000
@@ -56,13 +56,9 @@
rootsite='answers')
-class RosettaApplicationView(TranslationsMixin):
+class RosettaApplicationView(LaunchpadView, TranslationsMixin):
"""View for various top-level Translations pages."""
- def __init__(self, context, request):
- self.context = context
- self.request = request
-
@property
def ubuntu_translationseries(self):
ubuntu = getUtility(ILaunchpadCelebrities).ubuntu