Merge lp:~mwhudson/launchpad/vostok-traverse-distro into lp:launchpad

Proposed by Michael Hudson-Doyle
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 11327
Proposed branch: lp:~mwhudson/launchpad/vostok-traverse-distro
Merge into: lp:launchpad
Prerequisite: lp:~mwhudson/launchpad/vostok-main-template
Diff against target: 137 lines (+71/-2)
4 files modified
lib/lp/testing/factory.py (+5/-2)
lib/lp/vostok/browser/configure.zcml (+5/-0)
lib/lp/vostok/publisher.py (+18/-0)
lib/lp/vostok/tests/test_navigation.py (+43/-0)
To merge this branch: bzr merge lp:~mwhudson/launchpad/vostok-traverse-distro
Reviewer Review Type Date Requested Status
Tim Penhey (community) Approve
Robert Collins (community) Needs Fixing
Review via email: mp+31241@code.launchpad.net

Commit message

Add a navigation for the vostok root that allows you to traverse to distributions

Description of the change

Hi,

This branch adds a navigation for the vostok root that allows you to traverse
to distributions.

Cheers,
mwh

To post a comment you must log in.
Revision history for this message
Tim Penhey (thumper) wrote :

Agh - perhaps it is just me, but __get_item__ on I<any>Set just seems wrong to
me.

> return self.redirectSubTree(canonical_url(distro), status=301)

That will take the user out of the vostok vhost. Is that what you want?

If not, you probably want to set the root as part of the canonical_url call.

review: Needs Information
Revision history for this message
Robert Collins (lifeless) wrote :

This change is faulty:

- 'Unrecognized branch type: %r' % (branch_type,))
+ 'Unrecognized branch type: %r' % branch_type)

if branch_type is a tuple with length != 1, it will blow up in your version, and for a error code path thats undesirable. I haven't done a full review - was glancing in email and this jumped out at me.

review: Needs Fixing
Revision history for this message
Tim Penhey (thumper) wrote :

On Fri, 30 Jul 2010 16:04:43 you wrote:
> Review: Needs Fixing
>
> This change is faulty:
>
> - 'Unrecognized branch type: %r' % (branch_type,))
> + 'Unrecognized branch type: %r' % branch_type)
>
> if branch_type is a tuple with length != 1, it will blow up in your
> version, and for a error code path thats undesirable. I haven't done a
> full review - was glancing in email and this jumped out at me.

Yeah, but branch_type is always a BranchType enum value, which is why I let
this slide.

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

On Thu, 29 Jul 2010 23:44:46 -0000, Tim Penhey <email address hidden> wrote:
> Review: Needs Information
> Agh - perhaps it is just me, but __get_item__ on I<any>Set just seems wrong to
> me.

Changed to getByName.

> > return self.redirectSubTree(canonical_url(distro), status=301)
>
> That will take the user out of the vostok vhost. Is that what you want?

Actually it won't.

> If not, you probably want to set the root as part of the canonical_url call.

I think canonical_url looks at the current request to find the root
site.

I also made the change Rob suggested.

Cheers,
mwh

Revision history for this message
Robert Collins (lifeless) wrote :

On Fri, Jul 30, 2010 at 6:33 AM, Tim Penhey <email address hidden> wrote:

>> if branch_type is a tuple with length != 1, it will blow up in your
>> version, and for a error code path thats undesirable. I haven't done a
>> full review - was glancing in email and this jumped out at me.
>
> Yeah, but branch_type is always a BranchType enum value, which is why I let
> this slide.

From IRC - its good to keep reflexes from having to deal with false
signals - while its true here that its always not a tuple, in the
general case we should be wary of direct substitution like this, so
its nice to have it clearly safe.

-Rob

Revision history for this message
Guilherme Salgado (salgado) wrote :

lib/lp/vostok/tests/test_navigation.py will break when you merge devel because NotFoundError was moved to lp.app.errors. I've noticed that because I have a branch which adds more stuff on top of this one.

Revision history for this message
Tim Penhey (thumper) wrote :

You should import NotFound from lp.app.errors, but apart from that it looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/testing/factory.py'
--- lib/lp/testing/factory.py 2010-08-05 21:25:12 +0000
+++ lib/lp/testing/factory.py 2010-08-06 02:38:50 +0000
@@ -1669,7 +1669,7 @@
1669 return library_file_alias1669 return library_file_alias
16701670
1671 def makeDistribution(self, name=None, displayname=None, owner=None,1671 def makeDistribution(self, name=None, displayname=None, owner=None,
1672 members=None, title=None):1672 members=None, title=None, aliases=None):
1673 """Make a new distribution."""1673 """Make a new distribution."""
1674 if name is None:1674 if name is None:
1675 name = self.getUniqueString()1675 name = self.getUniqueString()
@@ -1684,9 +1684,12 @@
1684 owner = self.makePerson()1684 owner = self.makePerson()
1685 if members is None:1685 if members is None:
1686 members = self.makeTeam(owner)1686 members = self.makeTeam(owner)
1687 return getUtility(IDistributionSet).new(1687 distro = getUtility(IDistributionSet).new(
1688 name, displayname, title, description, summary, domainname,1688 name, displayname, title, description, summary, domainname,
1689 members, owner)1689 members, owner)
1690 if aliases is not None:
1691 removeSecurityProxy(distro).setAliases(aliases)
1692 return distro
16901693
1691 def makeDistroRelease(self, distribution=None, version=None,1694 def makeDistroRelease(self, distribution=None, version=None,
1692 status=SeriesStatus.DEVELOPMENT,1695 status=SeriesStatus.DEVELOPMENT,
16931696
=== modified file 'lib/lp/vostok/browser/configure.zcml'
--- lib/lp/vostok/browser/configure.zcml 2010-07-15 08:55:32 +0000
+++ lib/lp/vostok/browser/configure.zcml 2010-08-06 02:38:50 +0000
@@ -27,4 +27,9 @@
27 layer="lp.vostok.publisher.VostokLayer"27 layer="lp.vostok.publisher.VostokLayer"
28 />28 />
2929
30 <browser:navigation
31 module="lp.vostok.publisher"
32 classes="VostokRootNavigation"
33 />
34
30</configure>35</configure>
3136
=== modified file 'lib/lp/vostok/publisher.py'
--- lib/lp/vostok/publisher.py 2010-07-30 03:50:17 +0000
+++ lib/lp/vostok/publisher.py 2010-08-06 02:38:50 +0000
@@ -7,19 +7,24 @@
7__all__ = [7__all__ = [
8 'VostokBrowserRequest',8 'VostokBrowserRequest',
9 'VostokLayer',9 'VostokLayer',
10 'VostokRootNavigation',
10 'vostok_request_publication_factory',11 'vostok_request_publication_factory',
11 ]12 ]
1213
1314
15from zope.component import getUtility
14from zope.interface import implements, Interface16from zope.interface import implements, Interface
15from zope.publisher.interfaces.browser import (17from zope.publisher.interfaces.browser import (
16 IBrowserRequest, IDefaultBrowserLayer)18 IBrowserRequest, IDefaultBrowserLayer)
1719
20from canonical.launchpad.webapp import canonical_url, Navigation
18from canonical.launchpad.webapp.publication import LaunchpadBrowserPublication21from canonical.launchpad.webapp.publication import LaunchpadBrowserPublication
19from canonical.launchpad.webapp.servers import (22from canonical.launchpad.webapp.servers import (
20 LaunchpadBrowserRequest, VirtualHostRequestPublicationFactory)23 LaunchpadBrowserRequest, VirtualHostRequestPublicationFactory)
21from canonical.launchpad.webapp.vhosts import allvhosts24from canonical.launchpad.webapp.vhosts import allvhosts
2225
26from lp.registry.interfaces.distribution import IDistributionSet
27
2328
24class VostokLayer(IBrowserRequest, IDefaultBrowserLayer):29class VostokLayer(IBrowserRequest, IDefaultBrowserLayer):
25 """The Vostok layer."""30 """The Vostok layer."""
@@ -53,6 +58,19 @@
53 implements(IVostokRoot)58 implements(IVostokRoot)
5459
5560
61class VostokRootNavigation(Navigation):
62
63 usedfor = IVostokRoot
64
65 def traverse(self, name):
66 distro = getUtility(IDistributionSet)[name]
67 if distro is not None and distro.name != name:
68 # This distro was accessed through one of its aliases, so we
69 # must redirect to its canonical URL.
70 return self.redirectSubTree(canonical_url(distro), status=301)
71 return distro
72
73
56class VostokBrowserPublication(LaunchpadBrowserPublication):74class VostokBrowserPublication(LaunchpadBrowserPublication):
57 root_object_interface = IVostokRoot75 root_object_interface = IVostokRoot
5876
5977
=== added file 'lib/lp/vostok/tests/test_navigation.py'
--- lib/lp/vostok/tests/test_navigation.py 1970-01-01 00:00:00 +0000
+++ lib/lp/vostok/tests/test_navigation.py 2010-08-06 02:38:50 +0000
@@ -0,0 +1,43 @@
1# Copyright 2010 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).
3
4"""Tests for vostok's root navigation."""
5
6__metaclass__ = type
7
8from zope.publisher.interfaces import NotFound
9from zope.security.proxy import removeSecurityProxy
10
11from canonical.launchpad.webapp import urlparse
12from canonical.testing.layers import DatabaseFunctionalLayer
13
14from lp.testing import TestCaseWithFactory
15from lp.testing.publication import test_traverse
16
17
18class TestRootNavigation(TestCaseWithFactory):
19
20 layer = DatabaseFunctionalLayer
21
22 def test_traverse_to_distributions(self):
23 # We can traverse to a distribution by name from the vostok
24 # root.
25 distro = self.factory.makeDistribution()
26 obj, view, request = test_traverse('http://vostok.dev/' + distro.name)
27 self.assertEqual(distro, obj)
28
29 def test_traverse_to_distribution_aliases(self):
30 # When we traverse to a distribution using one of its aliases, we're
31 # redirected to the distribution's page on the vostok vhost.
32 distro = self.factory.makeDistribution(aliases=['f00'])
33 obj, view, request = test_traverse('http://vostok.dev/f00')
34 naked_view = removeSecurityProxy(view)
35 parse_result = urlparse(naked_view.target)
36 self.assertEqual('vostok.dev', parse_result.netloc)
37 self.assertEqual('/' + distro.name, parse_result.path)
38
39 def test_can_not_traverse_to_projects(self):
40 # We cannot traverse to a project from the vostok root.
41 path = self.factory.makeProject().name
42 self.assertRaises(
43 NotFound, test_traverse, 'http://vostok.dev/' + path)