launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26521
[Merge] ~pappacena/launchpad:snap-pillar-product-url into launchpad:master
Thiago F. Pappacena has proposed merging ~pappacena/launchpad:snap-pillar-product-url into launchpad:master with ~pappacena/launchpad:snap-pillar-list-filters as a prerequisite.
Commit message:
Redirecting snaps with pillar to stay under ~user/pillar URL
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pappacena/launchpad/+git/launchpad/+merge/399025
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pappacena/launchpad:snap-pillar-product-url into launchpad:master.
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 31c29ed..f1bb302 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Person-related view classes."""
@@ -69,6 +69,7 @@ import six
from six.moves.urllib.parse import (
quote,
urlencode,
+ urljoin,
)
from storm.zope.interfaces import IResultSet
from zope.browserpage import ViewPageTemplateFile
@@ -647,7 +648,17 @@ class PersonNavigation(BranchTraversalMixin, Navigation):
@stepthrough('+snap')
def traverse_snap(self, name):
"""Traverse to this person's snap packages."""
- return getUtility(ISnapSet).getByName(self.context, name)
+ snap = getUtility(ISnapSet).getByName(self.context, name)
+ # If it's a snap attached to a pillar, redirect to the Snap
+ # URL under pillar's URL.
+ if snap.project:
+ person_product = getUtility(IPersonProductFactory).create(
+ self.context, snap.project)
+ project_url = canonical_url(person_product)
+ snap_url = urljoin(project_url + '/', '+snap/')
+ snap_url = urljoin(snap_url, snap.name)
+ return self.redirectSubTree(snap_url)
+ return snap
class PersonSetNavigation(Navigation):
diff --git a/lib/lp/registry/browser/personproduct.py b/lib/lp/registry/browser/personproduct.py
index a249b27..7d850e3 100644
--- a/lib/lp/registry/browser/personproduct.py
+++ b/lib/lp/registry/browser/personproduct.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2021 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Views, menus and traversal related to PersonProducts."""
@@ -30,6 +30,7 @@ from lp.services.webapp import (
)
from lp.services.webapp.breadcrumb import Breadcrumb
from lp.services.webapp.interfaces import IMultiFacetedBreadcrumb
+from lp.snappy.interfaces.snap import ISnapSet
class PersonProductNavigation(PersonTargetDefaultVCSNavigationMixin,
@@ -53,6 +54,13 @@ class PersonProductNavigation(PersonTargetDefaultVCSNavigationMixin,
else:
return branch
+ @stepthrough('+snap')
+ def traverse_snap(self, name):
+ return getUtility(ISnapSet).getByPillarAndName(
+ owner=self.context.person,
+ pillar=self.context.product,
+ name=name)
+
@implementer(IMultiFacetedBreadcrumb)
class PersonProductBreadcrumb(Breadcrumb):
diff --git a/lib/lp/snappy/browser/tests/test_snap.py b/lib/lp/snappy/browser/tests/test_snap.py
index 61f514a..a8586a2 100644
--- a/lib/lp/snappy/browser/tests/test_snap.py
+++ b/lib/lp/snappy/browser/tests/test_snap.py
@@ -58,6 +58,7 @@ from lp.code.tests.helpers import (
)
from lp.registry.enums import (
BranchSharingPolicy,
+ BranchSharingPolicy,
PersonVisibility,
TeamMembershipPolicy,
)
@@ -1521,6 +1522,15 @@ class TestSnapView(BaseTestSnapView):
"snap breadcrumb", "li",
text=re.compile(r"\ssnap-name\s")))))
+ def test_snap_with_project_pillar_redirects(self):
+ project = self.factory.makeProduct()
+ snap = self.factory.makeSnap(project=project)
+ browser = self.getViewBrowser(snap)
+ with admin_logged_in():
+ expected_url = 'http://launchpad.test/~{}/{}/+snap/{}'.format(
+ snap.owner.name, project.name, snap.name)
+ self.assertEqual(expected_url, browser.url)
+
def test_index_bzr(self):
branch = self.factory.makePersonalBranch(
owner=self.person, name="snap-branch")
diff --git a/lib/lp/snappy/browser/tests/test_snapsubscription.py b/lib/lp/snappy/browser/tests/test_snapsubscription.py
index ef021d9..b091e95 100644
--- a/lib/lp/snappy/browser/tests/test_snapsubscription.py
+++ b/lib/lp/snappy/browser/tests/test_snapsubscription.py
@@ -9,6 +9,9 @@ __metaclass__ = type
from fixtures import FakeLogger
+from lp.registry.interfaces.personproduct import IPersonProductFactory
+from six.moves.urllib.parse import urljoin
+from zope.component._api import getUtility
from zope.security.interfaces import Unauthorized
from lp.app.enums import InformationType
@@ -65,6 +68,17 @@ class BaseTestSnapView(BrowserTestCase):
class TestPublicSnapSubscriptionViews(BaseTestSnapView):
+ def getSnapURL(self, snap):
+ with admin_logged_in():
+ if snap.project:
+ person_product = getUtility(IPersonProductFactory).create(
+ snap.owner, snap.project)
+ project_url = canonical_url(person_product)
+ snap_url = urljoin(project_url + '/', '+snap/')
+ return urljoin(snap_url, snap.name)
+ else:
+ return canonical_url(snap)
+
def test_subscribe_self(self):
snap = self.makeSnap()
another_user = self.factory.makePerson(name="another-user")
@@ -87,8 +101,7 @@ class TestPublicSnapSubscriptionViews(BaseTestSnapView):
browser.getControl("Subscribe").click()
# We should be redirected back to snap page.
- with admin_logged_in():
- self.assertEqual(canonical_url(snap), browser.url)
+ self.assertEqual(self.getSnapURL(snap), browser.url)
# And the new user should be listed in the subscribers list.
self.assertTextMatchesExpressionIgnoreWhitespace(r"""
@@ -148,8 +161,7 @@ class TestPublicSnapSubscriptionViews(BaseTestSnapView):
browser.getControl("Subscribe").click()
# We should be redirected back to snap page.
- with admin_logged_in():
- self.assertEqual(canonical_url(snap), browser.url)
+ self.assertEqual(self.getSnapURL(snap), browser.url)
# And the new user should be listed in the subscribers list.
self.assertTextMatchesExpressionIgnoreWhitespace(r"""
diff --git a/lib/lp/snappy/interfaces/snap.py b/lib/lp/snappy/interfaces/snap.py
index c33ea82..e2d6c14 100644
--- a/lib/lp/snappy/interfaces/snap.py
+++ b/lib/lp/snappy/interfaces/snap.py
@@ -966,6 +966,9 @@ class ISnapSet(Interface):
def getByName(owner, name):
"""Return the appropriate `ISnap` for the given objects."""
+ def getByPillarAndName(owner, pillar, name):
+ """Returns the appropriate `ISnap` for the given pillar and name."""
+
@operation_parameters(
owner=Reference(IPerson, title=_("Owner"), required=True))
@operation_returns_collection_of(ISnap)
diff --git a/lib/lp/snappy/model/snap.py b/lib/lp/snappy/model/snap.py
index f0cbf07..fd92f93 100644
--- a/lib/lp/snappy/model/snap.py
+++ b/lib/lp/snappy/model/snap.py
@@ -1437,6 +1437,14 @@ class SnapSet:
raise NoSuchSnap(name)
return snap
+ def getByPillarAndName(self, owner, pillar, name):
+ conditions = [Snap.owner == owner, Snap.name == name]
+ if IProduct.providedBy(pillar):
+ conditions.append(Snap.project == pillar)
+ else:
+ raise NotImplementedError("Unknown pillar for snap: %s" % pillar)
+ return IStore(Snap).find(Snap, *conditions).one()
+
def _getSnapsFromCollection(self, collection, owner=None,
visible_by_user=None):
if IBranchCollection.providedBy(collection):
diff --git a/lib/lp/snappy/tests/test_snap.py b/lib/lp/snappy/tests/test_snap.py
index 80bcaf4..528c0fa 100644
--- a/lib/lp/snappy/tests/test_snap.py
+++ b/lib/lp/snappy/tests/test_snap.py
@@ -69,6 +69,7 @@ from lp.code.tests.helpers import (
)
from lp.registry.enums import (
BranchSharingPolicy,
+ BranchSharingPolicy,
PersonVisibility,
TeamMembershipPolicy,
)
@@ -2858,9 +2859,13 @@ class TestSnapWebservice(TestCaseWithFactory):
branch = self.factory.makeAnyBranch(
owner=self.person,
information_type=InformationType.PRIVATESECURITY)
+ project = self.factory.makeProduct(
+ owner=self.person, registrant=self.person,
+ information_type=InformationType.PROPRIETARY,
+ branch_sharing_policy=BranchSharingPolicy.PROPRIETARY)
snap = self.factory.makeSnap(
registrant=self.person, owner=self.person, branch=branch,
- private=True)
+ project=project, information_type=InformationType.PROPRIETARY)
admin = getUtility(ILaunchpadCelebrities).admin.teamowner
with person_logged_in(self.person):
snap_url = api_url(snap)
@@ -2868,9 +2873,13 @@ class TestSnapWebservice(TestCaseWithFactory):
admin_webservice = webservice_for_person(
admin, permission=OAuthPermission.WRITE_PRIVATE)
admin_webservice.default_api_version = "devel"
- response = admin_webservice.patch(
- snap_url, "application/json",
- json.dumps({"information_type": 'Public'}))
+ data = json.dumps({"information_type": 'Public'})
+ content_type = "application/json"
+ response = admin_webservice.patch(snap_url, content_type, data)
+ # If it's a redirect, try again.
+ if response.status == 301:
+ location = urlsplit(response.getheader('location')).path
+ response = admin_webservice.patch(location, content_type, data)
self.assertEqual(400, response.status)
self.assertEqual(
b"Snap recipe contains private information and cannot be public.",
diff --git a/lib/lp/snappy/tests/test_snapbuild.py b/lib/lp/snappy/tests/test_snapbuild.py
index 7acff54..8404c86 100644
--- a/lib/lp/snappy/tests/test_snapbuild.py
+++ b/lib/lp/snappy/tests/test_snapbuild.py
@@ -17,6 +17,7 @@ from pymacaroons import Macaroon
import pytz
import six
from six.moves.urllib.request import urlopen
+from six.moves.urllib.parse import urlsplit
from testtools.matchers import (
ContainsDict,
Equals,
@@ -789,7 +790,11 @@ class TestSnapBuildWebservice(TestCaseWithFactory):
self.factory.makePerson(), permission=OAuthPermission.WRITE_PUBLIC)
unpriv_webservice.default_api_version = "devel"
logout()
- self.assertEqual(200, self.webservice.get(build_url).status)
+ response = self.webservice.get(build_url)
+ if response.status == 301:
+ location = urlsplit(response.getheader('location')).path
+ response = self.webservice.get(location)
+ self.assertEqual(200, response.status)
# 404 since we aren't allowed to know that the private team exists.
self.assertEqual(404, unpriv_webservice.get(build_url).status)
Follow ups