Colin Watson has proposed merging ~cjwatson/launchpad:series-urls into launchpad:master.
Commit message: Add alternate <pillar>/+series/<name> URLs Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/385489 These may be used instead of <pillar>/<name> URLs. For now they just redirect to the classic URLs, but that may change later. -- Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:series-urls into launchpad:master.
diff --git a/lib/lp/registry/browser/distribution.py b/lib/lp/registry/browser/distribution.py index ffabedb..29eab7a 100644 --- a/lib/lp/registry/browser/distribution.py +++ b/lib/lp/registry/browser/distribution.py @@ -121,7 +121,6 @@ from lp.services.webapp import ( canonical_url, ContextMenu, enabled_with_permission, - GetitemNavigation, LaunchpadView, Link, Navigation, @@ -140,7 +139,7 @@ from lp.soyuz.interfaces.archive import IArchiveSet class DistributionNavigation( - GetitemNavigation, BugTargetTraversalMixin, QuestionTargetTraversalMixin, + Navigation, BugTargetTraversalMixin, QuestionTargetTraversalMixin, FAQTargetNavigationMixin, StructuralSubscriptionTargetTraversalMixin, PillarNavigationMixin, TargetDefaultVCSNavigationMixin): @@ -178,12 +177,24 @@ class DistributionNavigation( def traverse_archive(self, name): return self.context.getArchive(name) - def traverse(self, name): + def _resolveSeries(self, name): try: - return super(DistributionNavigation, self).traverse(name) + return self.context[name], False except NotFoundError: resolved = self.context.resolveSeriesAlias(name) - return self.redirectSubTree(canonical_url(resolved), status=303) + return resolved, True + + @stepthrough('+series') + def traverse_series(self, name): + series, _ = self._resolveSeries(name) + return self.redirectSubTree(canonical_url(series), status=303) + + def traverse(self, name): + series, is_alias = self._resolveSeries(name) + if is_alias: + return self.redirectSubTree(canonical_url(series), status=303) + else: + return series class DistributionSetNavigation(Navigation): diff --git a/lib/lp/registry/browser/product.py b/lib/lp/registry/browser/product.py index c059dbb..5c3ebce 100644 --- a/lib/lp/registry/browser/product.py +++ b/lib/lp/registry/browser/product.py @@ -1,4 +1,4 @@ -# Copyright 2009-2018 Canonical Ltd. This software is licensed under the +# Copyright 2009-2020 Canonical Ltd. This software is licensed under the # GNU Affero General Public License version 3 (see the file LICENSE). """Browser views for products.""" @@ -275,6 +275,11 @@ class ProductNavigation( def traverse_commercialsubscription(self, name): return self.context.commercial_subscription + @stepthrough('+series') + def traverse_series(self, name): + series = self.context.getSeries(name) + return self.redirectSubTree(canonical_url(series), status=303) + def traverse(self, name): return self.context.getSeries(name) diff --git a/lib/lp/registry/browser/tests/test_distribution.py b/lib/lp/registry/browser/tests/test_distribution.py index 0979ec2..f7f37fd 100644 --- a/lib/lp/registry/browser/tests/test_distribution.py +++ b/lib/lp/registry/browser/tests/test_distribution.py @@ -17,11 +17,13 @@ from testtools.matchers import ( Not, ) from zope.schema.vocabulary import SimpleVocabulary +from zope.security.proxy import removeSecurityProxy from lp.app.browser.lazrjs import vocabulary_to_choice_edit_items from lp.registry.enums import EXCLUSIVE_TEAM_POLICY from lp.registry.interfaces.series import SeriesStatus from lp.services.webapp import canonical_url +from lp.services.webapp.publisher import RedirectionView from lp.testing import ( admin_logged_in, BrowserTestCase, @@ -30,15 +32,61 @@ from lp.testing import ( record_two_runs, TestCaseWithFactory, ) -from lp.testing.layers import DatabaseFunctionalLayer +from lp.testing.layers import ( + DatabaseFunctionalLayer, + ZopelessDatabaseLayer, + ) from lp.testing.pages import ( extract_text, find_tag_by_id, find_tags_by_class, ) +from lp.testing.publication import test_traverse from lp.testing.views import create_initialized_view +class TestDistributionNavigation(TestCaseWithFactory): + + layer = ZopelessDatabaseLayer + + def assertRedirects(self, url, expected_url): + _, view, _ = test_traverse(url) + self.assertIsInstance(view, RedirectionView) + self.assertEqual(expected_url, removeSecurityProxy(view).target) + + def test_classic_series_url(self): + distroseries = self.factory.makeDistroSeries() + obj, _, _ = test_traverse( + "http://launchpad.test/%s/%s" % ( + distroseries.distribution.name, distroseries.name)) + self.assertEqual(distroseries, obj) + + def test_classic_series_url_with_alias(self): + distroseries = self.factory.makeDistroSeries() + distroseries.distribution.development_series_alias = "devel" + self.assertRedirects( + "http://launchpad.test/%s/devel" % distroseries.distribution.name, + "http://launchpad.test/%s/%s" % ( + distroseries.distribution.name, distroseries.name)) + + def test_new_series_url_redirects(self): + distroseries = self.factory.makeDistroSeries() + self.assertRedirects( + "http://launchpad.test/%s/+series/%s" % ( + distroseries.distribution.name, distroseries.name), + "http://launchpad.test/%s/%s" % ( + distroseries.distribution.name, distroseries.name)) + + def test_new_series_url_with_alias_redirects(self): + distroseries = self.factory.makeDistroSeries() + distroseries.distribution.development_series_alias = "devel" + self.assertRedirects( + "http://launchpad.test/%s/+series/devel" % ( + distroseries.distribution.name), + "http://launchpad.test/%s/%s" % ( + distroseries.distribution.name, distroseries.name)) + + class TestDistributionPage(TestCaseWithFactory): """A TestCase for the distribution index page.""" diff --git a/lib/lp/registry/browser/tests/test_product.py b/lib/lp/registry/browser/tests/test_product.py index 4271302..cbf03bc 100644 --- a/lib/lp/registry/browser/tests/test_product.py +++ b/lib/lp/registry/browser/tests/test_product.py @@ -1,4 +1,4 @@ -# Copyright 2010-2019 Canonical Ltd. This software is licensed under the +# Copyright 2010-2020 Canonical Ltd. This software is licensed under the # GNU Affero General Public License version 3 (see the file LICENSE). """Tests for product views.""" @@ -52,7 +52,10 @@ from lp.registry.interfaces.product import ( from lp.registry.model.product import Product from lp.services.config import config from lp.services.database.interfaces import IStore -from lp.services.webapp.publisher import canonical_url +from lp.services.webapp.publisher import ( + canonical_url, + RedirectionView, + ) from lp.services.webapp.vhosts import allvhosts from lp.testing import ( BrowserTestCase, @@ -66,12 +69,14 @@ from lp.testing.fixture import DemoMode from lp.testing.layers import ( DatabaseFunctionalLayer, LaunchpadFunctionalLayer, + ZopelessDatabaseLayer, ) from lp.testing.matchers import HasQueryCount from lp.testing.pages import ( extract_text, find_tag_by_id, ) +from lp.testing.publication import test_traverse from lp.testing.service_usage_helpers import set_service_usage from lp.testing.views import ( create_initialized_view, @@ -79,6 +84,31 @@ from lp.testing.views import ( ) +class TestProductNavigation(TestCaseWithFactory): + + layer = ZopelessDatabaseLayer + + def assertRedirects(self, url, expected_url): + _, view, _ = test_traverse(url) + self.assertIsInstance(view, RedirectionView) + self.assertEqual(expected_url, removeSecurityProxy(view).target) + + def test_classic_series_url(self): + productseries = self.factory.makeProductSeries() + obj, _, _ = test_traverse( + "http://launchpad.test/%s/%s" % ( + productseries.product.name, productseries.name)) + self.assertEqual(productseries, obj) + + def test_new_series_url_redirects(self): + productseries = self.factory.makeProductSeries() + self.assertRedirects( + "http://launchpad.test/%s/+series/%s" % ( + productseries.product.name, productseries.name), + "http://launchpad.test/%s/%s" % ( + productseries.product.name, productseries.name)) + + class TestProductConfiguration(BrowserTestCase): """Tests the configuration links and helpers."""
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp